started to work on dashboard

This commit is contained in:
Dorian Zedler 2019-07-14 17:53:07 +02:00
parent 6bc5fba318
commit 9c619a9538
4 changed files with 273 additions and 41 deletions

View file

@ -120,3 +120,11 @@ body {
} }
} }
/*
*
*/
.opacity-animated {
-webkit-transition: opacity 1s; /* For Safari 3.1 to 6.0 */
transition: opacity 1s;
}

View file

@ -44,7 +44,7 @@
<div class="sidebar-sticky"> <div class="sidebar-sticky">
<ul class="nav flex-column"> <ul class="nav flex-column">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" id="navbarPage-1Link" onclick="setPage(-1)" href="#"> <a class="nav-link" id="navbarPage-1Link" onclick="dashboard.updateParams({page: -1})" href="#">
<span data-feather="home"></span> <span data-feather="home"></span>
Dashboard <span class="sr-only">(current)</span> Dashboard <span class="sr-only">(current)</span>
</a> </a>
@ -108,32 +108,50 @@
<div <div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2" id="titleH1">Dashboard</h1> <h1 class="h2" id="titleH1">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0"> <div class="btn-toolbar mb-2 mb-md-0" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button type="button" class="btn btn-sm btn-outline-secondary">Share</button> <button type="button" class="btn btn-sm btn-outline-secondary">Share</button>
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button> <button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
</div> </div>
<div class="dropdown" class="h-100">
<button id="dropdownMenuButton" type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle"
data-toggle="dropdown">
<span data-feather="calendar"></span>
<div class="btn-group mr-2" role="group">
</button> <div class="dropdown" class="h-100">
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton"> <button id="dropdownMenuButton" type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle"
<form class="px-4 py-3"> data-toggle="dropdown">
<span data-feather="calendar"></span>
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
<form class="px-4 py-3">
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(86400)">Today</button> <button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(86400)">Today</button>
<button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(604800)">This Week</button> <button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(604800)">This
<button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(18144000)">This Month</button> Week</button>
</div> <button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(18144000)">This
</form> Month</button>
<button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(18144000)">This
Year</button>
</div>
</form>
</div>
</div> </div>
</div> </div>
<div class="btn-group mr-2" role="group">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="dashboard.loadDashboard()">
<span data-feather="refresh-cw"></span>
</button>
</div>
</div> </div>
</div> </div>
<div id="mainContent" style="height: 100%"> <div id="loader" class="d-flex justify-content-center opacity-animated" style="position: absolute; left: 50%;">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div id="mainContent" class="opacity-animated" style="height: 100%">
</div> </div>
</div> </div>
</main> </main>

View file

@ -7,24 +7,36 @@ class BlueWeatherDashboard {
constructor() { constructor() {
// cunstruct xmlhttp // cunstruct xmlhttp
this.initDone = false
this.blueweather = new BlueWeather() this.blueweather = new BlueWeather()
this.loc = this.blueweather.findGetParameter("locId")
this.currentPage = -1 this.params = {
this.setPage(this.currentPage) loc: 1,
page: -1,
maxVals: 100
}
this.restoreParms(this.params)
this.setTimeRange()
this.loadDashboard(this.params)
this.initDone = true
} }
setPage(page) { loadDashboard() {
document.getElementById("navbarPage" + this.currentPage + "Link").classList.remove("active") window.history.pushState("object or string", "Title", this.buildUrl({ "params": JSON.stringify(this.params) }));
document.getElementById("navbarPage" + page + "Link").classList.add("active")
this.currentPage = page
// page: -1 for dashboard or sensor id // page: -1 for dashboard or sensor id
var mainContent = document.getElementById('mainContent') var mainContent = document.getElementById('mainContent')
var loader = document.getElementById('loader')
// set page to loading state mainContent.style = "opacity: 0;"
mainContent.innerHTML = "<div class=\"d-flex justify-content-center\"><div class=\"spinner-border\" role=\"status\"><span class=\"sr-only\">Loading...</span></div></div>" loader.style = "position: absolute; left: 50%; opacity: 1;"
//mainContent.classList.remove("opacity-animated");
this.blueweather.getLocationData(this.loc, undefined, undefined, true, function (locationData) { var page = this.params.page
this.blueweather.getLocationData(this.params.loc, { from: this.params.range.from, to: this.params.range.to }, this.params.maxVals, true, function (locationData) {
// refresh sensors list // refresh sensors list
dashboard.loadSensors(locationData.sensors) dashboard.loadSensors(locationData.sensors)
@ -33,21 +45,141 @@ class BlueWeatherDashboard {
if (page === -1) { if (page === -1) {
dashboard.setPageTitle("Dashboard") dashboard.setPageTitle("Dashboard")
mainContent.innerHTML = "<p>This is your great dashboard :))</p>"
var firstRow = document.createElement("div")
firstRow.classList.add("card-deck")
for (var i = 0; i < locationData.sensors.length; i++) {
var sensor = locationData.sensors[i]
// get the valuetype of the current sensor
var valueType;
for (var s = 0; s < locationData.valuetypes.length; s++) {
var thisValType = locationData.valuetypes[s]
if (parseInt(thisValType.id) === parseInt(sensor.valuetypeid)) {
valueType = thisValType;
break;
}
}
// get all relevant meassurement values
var vals = []
for (s = 0; s < locationData["measvalues"].length; s++) {
var thisValue = locationData["measvalues"][s]
if (parseInt(thisValue['sensorid']) === parseInt(sensor.id)) {
vals.push(thisValue)
}
}
if(vals.length < 1) {
continue
}
vals.sort(function(a,b){
return b.timestamp - a.timestamp
})
var latestVal = vals[0]
// - create html widget -
// create card
var thisWidget = document.createElement("div")
thisWidget.classList.add("card")
// create header
var thisHeader = document.createElement("div")
thisHeader.classList.add("card-header")
thisHeader.innerHTML = sensor.sensorname + " (" + valueType.valuetype + ")"
thisWidget.appendChild(thisHeader)
// create body
var thisBody = document.createElement("div")
thisBody.classList.add("card-body")
thisWidget.appendChild(thisBody)
// create footer
var thisFooter = document.createElement("div")
thisFooter.classList.add("card-footer")
// fill footer
var thisUpdateTime = document.createElement("small")
thisUpdateTime.classList.add("text-muted")
var lastUpdated = new Date(latestVal.timestamp * 1000)
thisUpdateTime.innerHTML = "last updated " + (lastUpdated.getDate() === new Date().getDate() ? "today" : lastUpdated.getFullYear+"-"+lastUpdated.getMonth()+"-"+lastUpdated.getDate()) + " at " + lastUpdated.getHours() + ":" + lastUpdated.getMinutes()
thisFooter.appendChild(thisUpdateTime)
thisWidget.appendChild(thisFooter)
// - create widget body -
var displayProperties = JSON.parse(valueType.displayproperty).widget
switch (displayProperties.type) {
case "doughnut":
// the widget is gauge-like
var thisChart = document.createElement("canvas")
thisChart.id = "chartOf" + sensor.sensorname
var chartData = {
datasets: [
{
label: sensor.sensorname + " (" + valueType.valuetype + ")",
data: [
parseInt(latestVal.measvalue),
100 -parseInt( latestVal.measvalue)
]
}
],
labels: false
}
Object.assign(chartData.datasets[0], displayProperties.properties)
dashboard.createPercentCircle(thisChart, chartData)
thisBody.appendChild(thisChart)
break
case "text":
// the widget is pure text
thisWidget.classList.add("text-center")
thisBody.innerHTML = '<h5 class="card-title">' + latestVal.measvalue + valueType.valueunit + '</h5>'
break
}
firstRow.appendChild(thisWidget)
}
mainContent.innerHTML = "";
mainContent.appendChild(firstRow)
} }
else if (page !== -1) { else if (page !== -1) {
dashboard.loadDiagram("mainContent", locationData, page) dashboard.loadDiagram("mainContent", locationData, page)
} }
})
loader.style = "position: absolute; left: 50%; opacity: 0;"
mainContent.classList.add("opacity-animated");
mainContent.style = "opacity: 1;"
})
}
restoreParms(defaults = {}) {
this.params = Object.assign(defaults, JSON.parse(this.findGetParameter("params")))
}
updateParams(newParams) {
if (newParams.page !== this.params.page && this.initDone) {
document.getElementById("navbarPage" + this.params.page + "Link").classList.remove("active")
}
Object.assign(this.params, newParams)
this.loadDashboard()
} }
setTimeRange(from = "", to = "") { setTimeRange(from = "", to = "") {
this.blueweather.log("changing time range; form: " + from + "; to: " + to + "; (now is: " + new Date().getTime() + ")", 3) this.blueweather.log("changing time range; form: " + from + "; to: " + to + "; (now is: " + new Date().getTime() + ")", 3)
// set page to loading state
mainContent.innerHTML = "<div class=\"d-flex justify-content-center\"><div class=\"spinner-border\" role=\"status\"><span class=\"sr-only\">Loading...</span></div></div>"
if (from !== "") { if (from !== "") {
from = new Date().getTime() / 1000 - from from = new Date().getTime() / 1000 - from
} }
@ -56,9 +188,7 @@ class BlueWeatherDashboard {
to = new Date().getTime() / 1000 - parseInt(to) to = new Date().getTime() / 1000 - parseInt(to)
} }
this.blueweather.getLocationData(this.loc, { from: from, to: to }, undefined, true, function (locationData) { this.updateParams({ range: { to: to, from: from } })
dashboard.loadDiagram("mainContent", locationData, dashboard.currentPage)
})
} }
@ -70,7 +200,7 @@ class BlueWeatherDashboard {
for (var i = 0; i < sensors.length; i++) { for (var i = 0; i < sensors.length; i++) {
var currentHTML = sensorsList.innerHTML var currentHTML = sensorsList.innerHTML
sensorsList.innerHTML = currentHTML + sensorsList.innerHTML = currentHTML +
"<li class=\"nav-item\"><a class=\"nav-link\" id=\"navbarPage" + sensors[i]["id"] + "Link\" href=\"#\" onclick=\"dashboard.setPage(" + sensors[i]["id"] + ")\"><span data-feather=\"file\"></span>" + sensors[i]["sensorname"] + "</a></li>" "<li class=\"nav-item\"><a class=\"nav-link\" id=\"navbarPage" + sensors[i]["id"] + "Link\" href=\"#\" onclick=\"dashboard.updateParams({page: " + sensors[i]["id"] + "})\"><span data-feather=\"file\"></span>" + sensors[i]["sensorname"] + "</a></li>"
} }
feather.replace() feather.replace()
@ -124,14 +254,14 @@ class BlueWeatherDashboard {
range: locationData.range range: locationData.range
} }
for (i = 0; i < vals.length; i++) { for (i = 0; i < vals.length; i++) {
chartData.data.push({ x: vals[i]["timestamp"], y: vals[i]["measvalue"] }) chartData.data.push({ x: vals[i]["timestamp"], y: vals[i]["measvalue"] })
} }
Object.assign(chartData.datasets[0], JSON.parse(valueType.displayproperty)) Object.assign(chartData.datasets[0], JSON.parse(valueType.displayproperty))
Object.assign(chartData.datasets[0], {data: chartData.data, pointRadius: chartData.data.length > 500 ? 0 : 3}) Object.assign(chartData.datasets[0], { data: chartData.data, pointRadius: chartData.data.length > 500 ? 0 : 3 })
mainContent.innerHTML = "<canvas class=\"my-4 w-100\" id=\"myChart\"></canvas>" mainContent.innerHTML = "<canvas class=\"my-4 w-100\" id=\"myChart\"></canvas>"
this.setPageTitle(sensor.sensorname + " (" + valueType.valuetype + ")") this.setPageTitle(sensor.sensorname + " (" + valueType.valuetype + ")")
@ -141,6 +271,39 @@ class BlueWeatherDashboard {
this.createDiagram("myChart", chartData) this.createDiagram("myChart", chartData)
} }
// --------------------
// - helper functions -
// --------------------
createPercentCircle(canvasElement, data) {
var randomScalingFactor = function () {
return Math.round(Math.random() * 100);
};
var ctx = canvasElement//document.getElementById(canvasId)
var chartData = data
var chartOptions = {
responsive: true,
circumference: Math.PI,
rotation: Math.PI,
legend: {
position: 'top',
},
animation: {
animateScale: true,
animateRotate: true
}
}
var myChart = new Chart(ctx, {
type: 'doughnut',
data: chartData,
options: chartOptions
})
}
createDiagram(canvasId, data) { createDiagram(canvasId, data) {
// Graphs // Graphs
var ctx = document.getElementById(canvasId) var ctx = document.getElementById(canvasId)
@ -233,6 +396,48 @@ class BlueWeatherDashboard {
setPageTitle(title) { setPageTitle(title) {
document.getElementById("titleH1").innerHTML = title document.getElementById("titleH1").innerHTML = title
} }
}
findGetParameter(parameterName) {
var result = null,
tmp = [];
location.search
.substr(1)
.split("&")
.forEach(function (item) {
tmp = item.split("=");
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
});
return result;
}
buildUrl(params) {
var basepath = window.location.href.split("?")[0]
basepath += "?"
for (var param in params) {
basepath += param + "=" + params[param] + "&"
}
return basepath
}
whichTransitionEvent() {
var t;
var el = document.createElement('fakeelement');
var transitions = {
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
'MozTransition': 'transitionend',
'WebkitTransition': 'webkitTransitionEnd'
}
for (t in transitions) {
if (el.style[t] !== undefined) {
return transitions[t];
}
}
}
}
dashboard = new BlueWeatherDashboard() dashboard = new BlueWeatherDashboard()

View file

@ -4,7 +4,6 @@
<head> <head>
<title>humidity Chart</title> <title>humidity Chart</title>
<script src="js/Chart.min.js"></script> <script src="js/Chart.min.js"></script>
<script src="js/utils.js"></script>
<style> <style>
canvas { canvas {
-moz-user-select: none; -moz-user-select: none;
@ -33,8 +32,8 @@
randomScalingFactor(), randomScalingFactor(),
], ],
backgroundColor: [ backgroundColor: [
window.chartColors.blue, 'rgb(54, 162, 235)',
window.chartColors.white, 'lightgrey',
], ],
label: 'Dataset 1' label: 'Dataset 1'
}], }],
@ -45,6 +44,8 @@
}, },
options: { options: {
responsive: true, responsive: true,
circumference: Math.PI,
rotation: Math.PI,
legend: { legend: {
position: 'top', position: 'top',
}, },