started to work on dashboard
This commit is contained in:
parent
6bc5fba318
commit
9c619a9538
4 changed files with 273 additions and 41 deletions
|
@ -120,3 +120,11 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
.opacity-animated {
|
||||
-webkit-transition: opacity 1s; /* For Safari 3.1 to 6.0 */
|
||||
transition: opacity 1s;
|
||||
}
|
|
@ -44,7 +44,7 @@
|
|||
<div class="sidebar-sticky">
|
||||
<ul class="nav flex-column">
|
||||
<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>
|
||||
Dashboard <span class="sr-only">(current)</span>
|
||||
</a>
|
||||
|
@ -108,32 +108,50 @@
|
|||
<div
|
||||
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>
|
||||
<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">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary">Share</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
|
||||
</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>
|
||||
|
||||
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
|
||||
<form class="px-4 py-3">
|
||||
<div class="btn-group mr-2" role="group">
|
||||
<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>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
|
||||
<form class="px-4 py-3">
|
||||
<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(604800)">This Week</button>
|
||||
<button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(18144000)">This Month</button>
|
||||
</div>
|
||||
</form>
|
||||
<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(18144000)">This
|
||||
Month</button>
|
||||
<button type="button" class="btn btn-light" onclick="dashboard.setTimeRange(18144000)">This
|
||||
Year</button>
|
||||
</div>
|
||||
</form>
|
||||
</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 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>
|
||||
</main>
|
||||
|
|
249
js/dashboard.js
249
js/dashboard.js
|
@ -7,24 +7,36 @@ class BlueWeatherDashboard {
|
|||
|
||||
constructor() {
|
||||
// cunstruct xmlhttp
|
||||
this.initDone = false
|
||||
this.blueweather = new BlueWeather()
|
||||
this.loc = this.blueweather.findGetParameter("locId")
|
||||
this.currentPage = -1
|
||||
this.setPage(this.currentPage)
|
||||
|
||||
this.params = {
|
||||
loc: 1,
|
||||
page: -1,
|
||||
maxVals: 100
|
||||
}
|
||||
|
||||
this.restoreParms(this.params)
|
||||
|
||||
this.setTimeRange()
|
||||
this.loadDashboard(this.params)
|
||||
this.initDone = true
|
||||
}
|
||||
|
||||
setPage(page) {
|
||||
document.getElementById("navbarPage" + this.currentPage + "Link").classList.remove("active")
|
||||
document.getElementById("navbarPage" + page + "Link").classList.add("active")
|
||||
loadDashboard() {
|
||||
window.history.pushState("object or string", "Title", this.buildUrl({ "params": JSON.stringify(this.params) }));
|
||||
|
||||
this.currentPage = page
|
||||
// page: -1 for dashboard or sensor id
|
||||
var mainContent = document.getElementById('mainContent')
|
||||
var loader = document.getElementById('loader')
|
||||
|
||||
// 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>"
|
||||
mainContent.style = "opacity: 0;"
|
||||
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
|
||||
dashboard.loadSensors(locationData.sensors)
|
||||
|
||||
|
@ -33,21 +45,141 @@ class BlueWeatherDashboard {
|
|||
|
||||
if (page === -1) {
|
||||
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) {
|
||||
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 = "") {
|
||||
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 !== "") {
|
||||
from = new Date().getTime() / 1000 - from
|
||||
}
|
||||
|
@ -56,9 +188,7 @@ class BlueWeatherDashboard {
|
|||
to = new Date().getTime() / 1000 - parseInt(to)
|
||||
}
|
||||
|
||||
this.blueweather.getLocationData(this.loc, { from: from, to: to }, undefined, true, function (locationData) {
|
||||
dashboard.loadDiagram("mainContent", locationData, dashboard.currentPage)
|
||||
})
|
||||
this.updateParams({ range: { to: to, from: from } })
|
||||
|
||||
}
|
||||
|
||||
|
@ -70,7 +200,7 @@ class BlueWeatherDashboard {
|
|||
for (var i = 0; i < sensors.length; i++) {
|
||||
var currentHTML = sensorsList.innerHTML
|
||||
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()
|
||||
|
@ -124,14 +254,14 @@ class BlueWeatherDashboard {
|
|||
range: locationData.range
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for (i = 0; i < vals.length; i++) {
|
||||
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], {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>"
|
||||
this.setPageTitle(sensor.sensorname + " (" + valueType.valuetype + ")")
|
||||
|
@ -141,6 +271,39 @@ class BlueWeatherDashboard {
|
|||
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) {
|
||||
// Graphs
|
||||
var ctx = document.getElementById(canvasId)
|
||||
|
@ -233,6 +396,48 @@ class BlueWeatherDashboard {
|
|||
setPageTitle(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()
|
|
@ -4,7 +4,6 @@
|
|||
<head>
|
||||
<title>humidity Chart</title>
|
||||
<script src="js/Chart.min.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
|
@ -33,8 +32,8 @@
|
|||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
window.chartColors.blue,
|
||||
window.chartColors.white,
|
||||
'rgb(54, 162, 235)',
|
||||
'lightgrey',
|
||||
],
|
||||
label: 'Dataset 1'
|
||||
}],
|
||||
|
@ -45,6 +44,8 @@
|
|||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
circumference: Math.PI,
|
||||
rotation: Math.PI,
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue