add aggregate.html
parent
b12aeb139b
commit
46e59006bd
@ -0,0 +1,145 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>openSenseMap Dataview</title>
|
||||
<style>
|
||||
body { font-family: sans; }
|
||||
th, td { padding: 10px; text-align: right; }
|
||||
tr:nth-child(odd) { background: #eee; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 id="title">loading ...</h1>
|
||||
<h4 id="subtitle"></h4>
|
||||
|
||||
<div>
|
||||
<button onclick="loadConfig('&phenomenon=Niederschlag&operation=sum')">Niederschlag</button>
|
||||
<button onclick="loadConfig('&phenomenon=Temperatur&operation=arithmeticMean')">ø Temperatur</button>
|
||||
<button onclick="loadConfig('&phenomenon=Temperatur&operation=max')">max. Temperatur</button>
|
||||
<button onclick="loadConfig('&phenomenon=Temperatur&operation=min')">min. Temperatur</button>
|
||||
<button onclick="loadConfig('&phenomenon=PM2.5&operation=max')">max. Feinstaub</button>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="loadConfig('&windowSize=30 days', reset=false)">Monat</button>
|
||||
<button onclick="loadConfig('&windowSize=1 week', reset=false)">Woche</button>
|
||||
<button onclick="loadConfig('&windowSize=1 day', reset=false)">Tag</button>
|
||||
<button onclick="loadConfig('&windowSize=1 hour', reset=false)">Stunde</button>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<div id="status"></div>
|
||||
|
||||
<table id="datatable"></table>
|
||||
|
||||
|
||||
<script>
|
||||
const defaultConfig = {
|
||||
boxId: '5b26181b1fef04001b69093c',
|
||||
phenomenon: 'Niederschlag',
|
||||
operation: 'sum',
|
||||
start: new Date('2019-04-01').toISOString(),
|
||||
end: new Date().toISOString(),
|
||||
windowSize: '30 days',
|
||||
}
|
||||
|
||||
const config = Object.assign(defaultConfig, parseHash())
|
||||
main(config).catch(console.error)
|
||||
|
||||
|
||||
async function main (config) {
|
||||
try {
|
||||
const data = await fetchOsemDataAggregate(config)
|
||||
|
||||
const table = document.querySelector('#datatable')
|
||||
populateTable(table, data, config)
|
||||
|
||||
const title = `${data['boxName']} - ${data['phenomenon']}`
|
||||
document.querySelector('#title').innerText = title
|
||||
document.title = title
|
||||
const subtitle = `${config.operation} per ${config.windowSize}`
|
||||
document.querySelector('#subtitle').innerText = subtitle
|
||||
} catch (err) {
|
||||
document.querySelector('#status').innerText = err
|
||||
}
|
||||
}
|
||||
|
||||
function parseHash () {
|
||||
const kvPairs = window.location.search
|
||||
// remove leading ?
|
||||
.slice(1)
|
||||
// create objects from kvpairs
|
||||
.split('&')
|
||||
.map(kv => {
|
||||
[k,v] = kv.split('=')
|
||||
return { [k]: decodeURIComponent(v) }
|
||||
})
|
||||
|
||||
return Object.assign.apply(null, kvPairs) // combine objects
|
||||
}
|
||||
|
||||
async function fetchOsemDataAggregate (config) {
|
||||
const {
|
||||
boxId,
|
||||
phenomenon,
|
||||
operation,
|
||||
start,
|
||||
end,
|
||||
windowSize,
|
||||
} = config
|
||||
|
||||
const url = `https://api.opensensemap.org/statistics/descriptive?boxid=${boxId}&from-date=${start}&to-date=${end}&phenomenon=${phenomenon}&window=${windowSize}&operation=${operation}&columns=boxName,unit,phenomenon&format=json&download=false`
|
||||
const res = await fetch(url)
|
||||
return (await res.json())[0]
|
||||
}
|
||||
|
||||
function populateTable (table, data, config) {
|
||||
const dateFormat = d => new Date(d).toLocaleDateString('de')
|
||||
const valFormat = v => Math.round(v * (10 ** 2)) / (10 ** 2)
|
||||
const addRow = (left, right) => {
|
||||
const row = document.createElement('tr')
|
||||
row.innerHTML = `<td>${left}</td><td>${right}</td>`
|
||||
table.appendChild(row)
|
||||
}
|
||||
|
||||
const dates = Object.keys(data).filter(k => k.startsWith('20')).sort()
|
||||
|
||||
for (let i = 0; i < dates.length; i++) {
|
||||
const dateFrom = dates[i]
|
||||
const dateTo = dates[i + 1] || new Date()
|
||||
const val = data[dates[i]]
|
||||
|
||||
const left = `${dateFormat(dateFrom)} - ${dateFormat(dateTo)}`
|
||||
const right = `${valFormat(val)} ${data['unit']}`
|
||||
addRow(left, right)
|
||||
}
|
||||
|
||||
// add aggregate of all values
|
||||
let aggregate = null
|
||||
switch (config.operation) {
|
||||
case 'sum':
|
||||
aggregate = dates.map(d => data[d]).reduce((s, v) => s += v, 0)
|
||||
break
|
||||
case 'arithmeticMean':
|
||||
aggregate = dates.map(d => data[d]).reduce((s, v) => s += v, 0) / dates.length
|
||||
break
|
||||
case 'max':
|
||||
aggregate = Math.max.apply(null, dates.map(d => data[d]))
|
||||
break
|
||||
case 'min':
|
||||
aggregate = Math.min.apply(null, dates.map(d => data[d]))
|
||||
break
|
||||
}
|
||||
if (aggregate)
|
||||
addRow(config.operation, `${valFormat(aggregate)} ${data['unit']}`)
|
||||
}
|
||||
|
||||
function loadConfig (queryString, reset = true) {
|
||||
if (reset)
|
||||
window.location.search = queryString
|
||||
else
|
||||
window.location.search += queryString
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue