Browse Source

add aggregate.html

master
Norwin 3 months ago
parent
commit
46e59006bd
2 changed files with 146 additions and 6 deletions
  1. 145
    0
      app/aggregate.html
  2. 1
    6
      app/assets/scripts/views/app.js

+ 145
- 0
app/aggregate.html View File

@@ -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>

+ 1
- 6
app/assets/scripts/views/app.js View File

@@ -13,11 +13,6 @@ var App = React.createClass({
},

render: function () {

const monthStart = new Date('2019-01-01').toISOString();
const monthEnd = new Date().toISOString();
const monthRainUrl = `https://api.opensensemap.org/statistics/descriptive?boxid=${config.senseBox.id}&from-date=${monthStart}&to-date=${monthEnd}&phenomenon=Niederschlag&window=30d&operation=sum&columns=boxName,unit&format=json&download=false`

return (
<div>
<header className='site-header' role='banner'>
@@ -27,7 +22,7 @@ var App = React.createClass({
<span>
<a target='_blank' href={'https://opensensemap.org/explore/' + config.senseBox.id}>🗺️ Karte</a>
<br/>
<a target='_blank' href={monthRainUrl}>Niederschlag / Monat</a>
<a href='./aggregate.html'>Daten-Aggregation</a>
</span>
</div>
</div>

Loading…
Cancel
Save