blueweather/js/dashboard.js

589 lines
17 KiB
JavaScript
Raw Normal View History

2019-07-11 14:53:18 +02:00
/* globals Chart:false, feather:false */
//var ctx = document.getElementById('myChart')
//var mainContent = document.getElementById('mainContent')
2019-07-13 20:02:04 +02:00
class BlueWeatherDashboard {
constructor() {
// cunstruct xmlhttp
2019-07-14 17:53:07 +02:00
this.initDone = false
2019-07-13 20:02:04 +02:00
this.blueweather = new BlueWeather()
2019-07-14 17:53:07 +02:00
this.params = {
loc: 1,
page: -1,
2019-07-14 22:02:35 +02:00
maxVals: 100,
range: {
from: "",
to: ""
}
2019-07-14 17:53:07 +02:00
}
this.restoreParms(this.params)
this.loadDashboard(this.params)
this.initDone = true
2019-07-13 20:02:04 +02:00
}
2019-07-14 17:53:07 +02:00
loadDashboard() {
window.history.pushState("object or string", "Title", this.buildUrl({ "params": JSON.stringify(this.params) }));
this.setTimeRange(this.params.from, this.params.to, false, false)
2019-07-13 20:02:04 +02:00
// page: -1 for dashboard or sensor id
var mainContent = document.getElementById('mainContent')
2019-07-14 17:53:07 +02:00
var loader = document.getElementById('loader')
2019-07-14 17:53:07 +02:00
mainContent.style = "opacity: 0;"
loader.style = "position: absolute; left: 50%; opacity: 1;"
//mainContent.classList.remove("opacity-animated");
2019-07-13 20:02:04 +02:00
2019-07-14 17:53:07 +02:00
var page = this.params.page
if(this.initDone){
document.getElementById("navbarPage" + page + "Link").classList.add("active")
}
2019-07-14 17:53:07 +02:00
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
2019-07-13 20:02:04 +02:00
dashboard.loadSensors(locationData.sensors)
2019-07-13 20:02:04 +02:00
// set acive page in navbar
document.getElementById("navbarPage" + page + "Link").classList.add("active")
if (page === -1) {
dashboard.setPageTitle("Dashboard")
2019-07-14 17:53:07 +02:00
2019-07-14 21:38:37 +02:00
// create widget row
2019-07-14 17:53:07 +02:00
var firstRow = document.createElement("div")
firstRow.classList.add("card-deck")
2019-07-14 21:38:37 +02:00
// create table
var tableContainer = document.createElement("div")
tableContainer.style = "overflow-x:auto;margin-top:20px;"
var table = document.createElement("table")
tableContainer.appendChild(table)
table.classList.add("table", "table-hover")
2019-07-14 21:38:37 +02:00
// create forst row of table
var tableHead = document.createElement("thead")
table.appendChild(tableHead)
tableHead.innerHTML = "<tr><th>Sensor</th><th>Minimum</th><th>Maximum</th><th>Average</th></tr>"
var tableBody = document.createElement("tbody")
table.appendChild(tableBody)
2019-07-14 17:53:07 +02:00
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 = []
2019-07-14 21:38:37 +02:00
var sum = 0
var min = undefined
var max = undefined
var avg = 0
2019-07-14 17:53:07 +02:00
for (s = 0; s < locationData["measvalues"].length; s++) {
var thisValue = locationData["measvalues"][s]
if (parseInt(thisValue['sensorid']) === parseInt(sensor.id)) {
vals.push(thisValue)
if (parseFloat(thisValue.measvalue) < min || min === undefined) {
min = parseFloat(thisValue.measvalue)
2019-07-14 21:38:37 +02:00
}
if (parseFloat(thisValue.measvalue) > max || max === undefined) {
max = parseFloat(thisValue.measvalue)
2019-07-14 21:38:37 +02:00
}
2019-07-14 17:53:07 +02:00
}
}
for (s = 0; s < vals.length; s++) {
avg += vals[s].measvalue / vals.length
}
if (vals.length < 1) {
2019-07-14 17:53:07 +02:00
continue
}
vals.sort(function (a, b) {
2019-07-14 17:53:07 +02:00
return b.timestamp - a.timestamp
})
2019-07-14 21:38:37 +02:00
// create table col
var tableRow = document.createElement("tr")
tableRow.innerHTML = "<td>" + sensor.sensorname + " (" + valueType.valuetype + ", " + valueType.valueunit + ")" + "</td><td>" + min + "</td><td>" + max + "</td><td>" + (Math.round((avg) * 100) / 100) + "</td>"
2019-07-14 21:38:37 +02:00
tableBody.appendChild(tableRow)
// - create widget card -
2019-07-14 17:53:07 +02:00
var latestVal = vals[0]
// 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()
2019-07-14 17:53:07 +02:00
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)
2019-07-14 17:53:07 +02:00
break
case "text":
// the widget is pure text
thisWidget.classList.add("text-center")
thisBody.innerHTML = '<h1 class="align-self-center mx-auto" style="font-size:10vw;margin-top: auto;margin-bottom: auto;">' + latestVal.measvalue + valueType.valueunit + '</h1>'
2019-07-14 18:51:43 +02:00
//thisBody.innerHTML = '<svg viewBox="0 0 56 18"><text x="0" y="15">Fit Meeeeeeeeeeee</text></svg>'
break
2019-07-14 17:53:07 +02:00
}
firstRow.appendChild(thisWidget)
}
2019-07-14 21:38:37 +02:00
2019-07-14 17:53:07 +02:00
mainContent.innerHTML = "";
mainContent.appendChild(firstRow)
2019-07-14 21:38:37 +02:00
mainContent.appendChild(tableContainer)
2019-07-13 20:02:04 +02:00
}
else if (page !== -1) {
2019-07-14 22:02:35 +02:00
mainContent.innerHTML = ""
dashboard.loadDiagram(mainContent, locationData, page)
2019-07-13 20:02:04 +02:00
}
2019-07-14 17:53:07 +02:00
loader.style = "position: absolute; left: 50%; opacity: 0;"
mainContent.classList.add("opacity-animated");
mainContent.style = "opacity: 1;"
2019-07-13 20:02:04 +02:00
})
2019-07-14 17:53:07 +02:00
}
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)
2019-07-14 21:38:37 +02:00
window.history.pushState("object or string", "Title", this.buildUrl({ "params": JSON.stringify(this.params) }));
2019-07-14 17:53:07 +02:00
this.loadDashboard()
}
setTimeRange(from = "", to = "", offset = true, autoReload = true) {
// offset: if true the gien times will be substracted from the current time to get the target time
2019-07-13 20:02:04 +02:00
this.blueweather.log("changing time range; form: " + from + "; to: " + to + "; (now is: " + new Date().getTime() + ")", 3)
if (offset) {
if (from !== "") {
from = new Date().getTime() / 1000 - from
}
if (to !== "") {
to = new Date().getTime() / 1000 - parseInt(to)
}
}
else {
if(from !== ""){
from = parseInt(from)
}
if(to !== ""){
to = parseInt(to)
}
}
var tmpFrom = from
var tmpTo = to
if(tmpFrom === "") {
tmpFrom = Math.round( new Date().getTime() / 1000 - 60 * 60 * 24 )
2019-07-13 20:02:04 +02:00
}
if(tmpTo === "") {
tmpTo = Math.round(new Date().getTime() / 1000)
2019-07-13 20:02:04 +02:00
}
var dateFromString = this.getDateTimeString(tmpFrom, tmpTo-tmpFrom)
var dateToString = this.getDateTimeString(tmpTo, tmpTo-tmpFrom)
dropdownMenuButton.innerHTML = "<span data-feather=\"calendar\"></span> " + dateFromString + " - " + dateToString
feather.replace()
if (this.initDone && autoReload) {
this.updateParams({ range: { to: to, from: from } })
}
}
2019-07-11 14:53:18 +02:00
2019-07-13 20:02:04 +02:00
loadSensors(sensors) {
2019-07-11 14:53:18 +02:00
2019-07-13 20:02:04 +02:00
var sensorsList = document.getElementById("sensorsList")
sensorsList.innerHTML = ""
2019-07-13 20:02:04 +02:00
for (var i = 0; i < sensors.length; i++) {
var currentHTML = sensorsList.innerHTML
sensorsList.innerHTML = currentHTML +
2019-07-14 17:53:07 +02:00
"<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>"
}
2019-07-13 20:02:04 +02:00
feather.replace()
}
2019-07-13 20:02:04 +02:00
loadDiagram(parentId, locationData, sensorId) {
if (typeof (parentId) === "string") {
2019-07-14 22:12:09 +02:00
var mainContent = document.getElementById(parentId)
2019-07-14 22:02:35 +02:00
}
else {
2019-07-14 22:12:09 +02:00
var mainContent = parentId
2019-07-14 22:02:35 +02:00
}
2019-07-13 20:02:04 +02:00
// get all relevant meassurement values
var vals = []
2019-07-13 20:02:04 +02:00
for (var i = 0; i < locationData["measvalues"].length; i++) {
var thisValue = locationData["measvalues"][i]
if (parseInt(thisValue['sensorid']) === sensorId) {
vals.push(thisValue)
}
}
2019-07-13 20:02:04 +02:00
// get the current sensor
var sensor;
2019-07-13 20:02:04 +02:00
for (i = 0; i < locationData['sensors'].length; i++) {
var thisSensor = locationData['sensors'][i]
if (parseInt(thisSensor.id) === sensorId) {
sensor = thisSensor;
break;
}
}
2019-07-13 20:02:04 +02:00
// get the value type
var valueType;
2019-07-13 20:02:04 +02:00
for (i = 0; i < locationData['valuetypes'].length; i++) {
var thisValType = locationData['valuetypes'][i]
if (parseInt(thisValType.id) === parseInt(sensor.valuetypeid)) {
valueType = thisValType;
break;
}
2019-07-13 20:02:04 +02:00
}
// build chart data array
var chartData = {
data: [],
datasets: [
{
2019-07-13 20:02:04 +02:00
label: sensor.sensorname + " (" + valueType.valuetype + ")",
yAxisID: 'yAxis',
showLine: true,
data: vals
}
2019-07-11 14:53:18 +02:00
],
2019-07-13 20:02:04 +02:00
range: locationData.range
}
2019-07-14 17:53:07 +02:00
2019-07-13 20:02:04 +02:00
for (i = 0; i < vals.length; i++) {
chartData.data.push({ x: vals[i]["timestamp"], y: vals[i]["measvalue"] })
}
2019-07-14 18:51:43 +02:00
Object.assign(chartData.datasets[0], JSON.parse(valueType.displayproperty)["chart"]["properties"])
2019-07-14 17:53:07 +02:00
Object.assign(chartData.datasets[0], { data: chartData.data, pointRadius: chartData.data.length > 500 ? 0 : 3 })
2019-07-13 20:02:04 +02:00
mainContent.innerHTML = "<canvas class=\"my-4 w-100\" id=\"myChart\"></canvas>"
this.setPageTitle(sensor.sensorname + " (" + valueType.valuetype + ")")
//blueweather.log("creating chart with data: " + JSON.stringify(chartData), 3)
this.createDiagram("myChart", chartData)
}
2019-07-14 17:53:07 +02:00
// --------------------
// - 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
})
}
2019-07-13 20:02:04 +02:00
createDiagram(canvasId, data) {
// Graphs
var ctx = document.getElementById(canvasId)
// eslint-disable-next-line no-unused-vars
var chartData = {
//labels: time,
datasets: data.datasets
};
var chartOptions = {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [
{
id: 'yAxis',
type: 'linear',
position: 'left',
}
],
xAxes: [{
ticks: {
min: parseInt(data.range.from),
max: parseInt(data.range.to),
beginAtZero: false,
stepSize: (data.range.to - data.range.from) / 10,
userCallback: function (label, index, labels) {
var d = new Date(parseInt(label) * 1000);
2019-07-14 21:38:37 +02:00
var datestr = "";
var to = data.range.to
var from = data.range.from
if (to === "") {
2019-07-14 21:38:37 +02:00
to = new Date().getTime()
}
var range = data.range.to - data.range.from
if (range <= 60 * 60 * 24) {
2019-07-14 21:38:37 +02:00
// covers one day or less
datestr = ("0" + d.getHours()).slice(-2) + ":" +
("0" + d.getMinutes()).slice(-2) + ":" +
("0" + d.getSeconds()).slice(-2)
2019-07-14 21:38:37 +02:00
}
else if (range <= 60 * 60 * 24 * 31) {
2019-07-14 21:38:37 +02:00
// covers one month or less
datestr = ("0" + d.getDate()).slice(-2) + "-" +
("0" + (d.getMonth() + 1)).slice(-2) + " " +
("0" + d.getHours()).slice(-2) + ":" +
("0" + d.getMinutes()).slice(-2) + ":" +
("0" + d.getSeconds()).slice(-2)
2019-07-14 21:38:37 +02:00
}
else {
// covers more than a month
datestr =
d.getFullYear() + "-" +
("0" + d.getDate()).slice(-2) + "-" +
("0" + (d.getMonth() + 1)).slice(-2)
2019-07-14 21:38:37 +02:00
}
2019-07-13 20:02:04 +02:00
return datestr;
}
},
scaleLabel: {
display: true,
labelString: 'time'
}
}],
},
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
var label = [data.datasets[tooltipItem.datasetIndex].label || ''];
if (label) {
label[0] += ': ';
}
label[0] += Math.round(tooltipItem.yLabel * 100) / 100;
2019-07-13 20:02:04 +02:00
var time = Math.round(tooltipItem.xLabel * 100) / 100;
var d = new Date(time * 1000);
var datestr =
d.getFullYear() + "-" +
2019-07-14 21:38:37 +02:00
("0" + d.getDate()).slice(-2) + "-" +
("0" + (d.getMonth() + 1)).slice(-2) + " " +
("0" + d.getHours()).slice(-2) + ":" +
("0" + d.getMinutes()).slice(-2) + ":" +
("0" + d.getSeconds()).slice(-2)
;
2019-07-13 20:02:04 +02:00
label.push("Time: " + datestr);
2019-07-13 20:02:04 +02:00
return label;
2019-07-11 14:53:18 +02:00
}
}
2019-07-11 14:53:18 +02:00
}
2019-07-13 20:02:04 +02:00
};
2019-07-13 20:02:04 +02:00
var myChart = new Chart(ctx, {
type: 'scatter',
data: chartData,
options: chartOptions
})
}
getDateTimeString(unixTime, range = 0) {
if(Math.abs(unixTime - new Date().getTime() / 1000) <= 60 ) {
return "now"
}
var d = new Date(parseInt(unixTime) * 1000);
var datestr = ""
if (range <= 60 * 60 * 24 * 31) {
// covers one month or less
datestr =
("0" + d.getDate()).slice(-2) + "-" +
("0" + (d.getMonth() + 1)).slice(-2) + " " +
("0" + d.getHours()).slice(-2) + ":" +
("0" + d.getMinutes()).slice(-2)
}
else {
// covers more than a month
datestr =
d.getFullYear() + "-" +
("0" + d.getDate()).slice(-2) + "-" +
("0" + (d.getMonth() + 1)).slice(-2)
}
return datestr
}
2019-07-13 20:02:04 +02:00
setPageTitle(title) {
document.getElementById("titleH1").innerHTML = title
}
2019-07-14 17:53:07 +02:00
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];
}
}
}
}
2019-07-11 14:53:18 +02:00
2019-07-14 19:02:55 +02:00
feather.replace()
2019-07-13 20:02:04 +02:00
dashboard = new BlueWeatherDashboard()