From aeeb6608236a4c8d4aca46a03cd19501f909b99f Mon Sep 17 00:00:00 2001 From: rxf Date: Fri, 31 Mar 2023 17:38:26 +0200 Subject: [PATCH] *** WIP WIP *** All charts work (mostly) --- actions/getsensorData.js | 2 +- sensorspecials/noise.js | 47 +++-- sensorspecials/noiseChart.js | 335 +++++++++++++++++++++++++++++++---- utilities/chartoptions.js | 7 +- 4 files changed, 333 insertions(+), 58 deletions(-) diff --git a/actions/getsensorData.js b/actions/getsensorData.js index 45142b5..ea1cb67 100644 --- a/actions/getsensorData.js +++ b/actions/getsensorData.js @@ -123,7 +123,7 @@ export async function getSensorData(params) { // distribute to the right routine for(let item of sensorTypeTable) { if(item.typ === erg.props.type) { - ret = item.func(params, item.possibleParams, erg.props) // get the values from database + ret = await item.func(params, item.possibleParams, erg.props) // get the values from database return ret } } diff --git a/sensorspecials/noise.js b/sensorspecials/noise.js index 5143f4f..e3ee2f0 100644 --- a/sensorspecials/noise.js +++ b/sensorspecials/noise.js @@ -196,7 +196,11 @@ async function getdavgData(opts) { } } } - werte.n_AVG = 10 * Math.log10(sum / count); + if (count === 0 ) { + werte.n_AVG = -1 + } else { + werte.n_AVG = 10 * Math.log10(sum / count); + } werte.peakcount = pk; if (opts.csv) { csvStr += werte.datetime + ',' + werte.n_AVG + ',' + werte.peakcount + '\n' @@ -207,8 +211,10 @@ async function getdavgData(opts) { } if (opts.csv) { return csvStr; - } else { + } else if (!opts.chart || erg.err) { return {err: erg.err, values: val} + } else { + return noiseChart.davgData(opts, val) } } @@ -243,10 +249,10 @@ async function getdavgData(opts) { // ********************************************* async function getdaynightData(opts) { opts.long = true; - let erg = await getNoiseAVGData(opts); + let erg = await getNoiseAVGData(opts); let val = []; let csvStr = 'datetime,n_dayAVG,n_nightAVG\n'; - if(!erg.err) { + if (!erg.err) { let done = false; let dt; // The received hourly data array always (!!) starts at 0h00 local (!) time. @@ -256,8 +262,8 @@ async function getdaynightData(opts) { let dsum = 0, dcnt = 0; let nsum = 0, ncnt = 0; let werte = {}; - const item = erg.values[i] for (let k = 0; k < 16; k++, i++) { + const item = erg.values[i] if (item.n_sum != -1) { if (werte.datetime === undefined) { let dt = DateTime.fromISO(item.datetime, {zone: 'utc'}) @@ -268,6 +274,7 @@ async function getdaynightData(opts) { } } if (i < (erg.values.length - 8)) { + const item = erg.values[i] for (let k = 0; k < 8; k++, i++) { if (item.n_sum != -1) { if (werte.datetime === undefined) { @@ -303,9 +310,12 @@ async function getdaynightData(opts) { } if (opts.csv) { return csvStr; - } else { + } else if (!opts.chart || erg.err) { return {err: erg.err, values: val} - } } + } else { + return noiseChart.dayNightData(opts, val) + } +} // ********************************************* // getLdenData @@ -358,20 +368,23 @@ async function getLdenData(opts) { let esum = 0, ecnt = 0; let werte = {}; let dayAVG = 0, evnAVG = 0, nightAVG = 0; - const item = erg.values[i] for (let k = 0; k < 12; k++, i++) { + const item = erg.values[i] if (item.n_sum != -1) { if (werte.datetime == undefined) { - werte.datetime = item.datetime; + let dt = DateTime.fromISO(item.datetime, {zone: 'utc'}) + werte.datetime = dt.startOf('day').toISO() } dsum += item.n_sum; dcnt += item.count; } } for (let k = 0; k < 4; k++, i++) { + const item = erg.values[i] if (item.n_sum != -1) { if (werte.datetime == undefined) { - werte.datetime = item.datetime; + let dt = DateTime.fromISO(item.datetime, {zone: 'utc'}) + werte.datetime = dt.startOf('day').toISO() } esum += item.n_sum; ecnt += item.count; @@ -379,9 +392,11 @@ async function getLdenData(opts) { } if (i < (erg.values.length - 8)) { for (let k = 0; k < 8; k++, i++) { + const item = erg.values[i] if (item.n_sum != -1) { if (werte.datetime == undefined) { - werte.datetime = item.datetime; + let dt = DateTime.fromISO(item.datetime, {zone: 'utc'}) + werte.datetime = dt.startOf('day').toISO() } nsum += item.n_sum; ncnt += item.count; @@ -410,8 +425,10 @@ async function getLdenData(opts) { } if (opts.csv) { return csvStr; - } else { + } else if (!opts.chart || erg.err) { return {err: erg.err, values: val} + } else { + return noiseChart.ldenData(opts, val) } } @@ -422,11 +439,11 @@ const getAPIprops = (opt) => { const getNoiseAVGData = async (opts) => { let ret = {err: null, values: []} - let emptyValues = {n_AVG:-1} + let emptyValues = {n_AVG: -1} let small = '|> keep(columns: ["_time", "peakcount", "n_AVG"])' if (opts.long) { small = '' - emptyValues = {n_sum: -1, n_AVG:-1} + emptyValues.n_sum = -1 } let queryAVG = ` import "math" @@ -505,7 +522,7 @@ peak = data const whatTable = [ {'what':'live', 'span': 1, 'daystart': false, peak: false, 'func': getLiveData}, - {'what':'havg', 'span': 7, 'daystart': true, peak: true, 'func': gethavgData}, + {'what':'havg', 'span': 3, 'daystart': false, peak: true, 'func': gethavgData}, {'what':'davg', 'span': 30, 'daystart': true, peak: true, 'func': getdavgData}, {'what':'daynight', 'span': 30, 'daystart': true, peak: false, 'func': getdaynightData}, {'what':'lden', 'span': 30, 'daystart': true, peak: false, 'func': getLdenData}, diff --git a/sensorspecials/noiseChart.js b/sensorspecials/noiseChart.js index b992111..e39f61e 100644 --- a/sensorspecials/noiseChart.js +++ b/sensorspecials/noiseChart.js @@ -1,6 +1,14 @@ // Prepare all data to plot the charts import * as utils from '../utilities/chartoptions.js' +/********************************************** + * Live-Data + * * + * @param params + * @param values + * @returns {{options: {plotOptions: {series: {marker: {enabled: boolean}, turboThreshold: number, animation: boolean}}, xAxis: {gridLineWidth: number, type: string, title: {text: string}, labels: {formatter: function(): (string|*)}}, legend: {layout: string, borderWidth: number, align: string, enabled: boolean}, subtitle: {align: string}, tooltip: {backgroundColor: number, valueDecimals: number, borderRadius: number, useHTML: boolean, borderWidth: number}, title: {useHTML: boolean, style: {fontSize: string}, align: string}, chart: {backgroundColor: {linearGradient: number[], stops: [[number,string],[number,string]]}, spacingTop: number, borderWidth: string, spacingLeft: number, type: string, spacingRight: number, events: {selection: function(*): void}, height: number}}, params}} + * + ***********************************************/ export const liveData = (params, values) => { let series1 = [] let series2 = [] @@ -146,13 +154,14 @@ export const liveData = (params, values) => { }, relativeTo: 'chart' } - options.tooltip.formatter = function () { - let y = Math.round(this.y * 100) / 100 - return '
' + - DateTime.fromMillis(this.x, {zone: 'utc'}).toFormat("dd.LL - HH:mm:ss") + '
' + - '● ' + - this.series.name + ':  ' + y + '
' - } + + // options.tooltip.formatter = function () { + // let y = Math.round(this.y * 100) / 100 + // return '
' + + // DateTime.fromMillis(this.x, {zone: 'utc'}).toFormat("dd.LL - HH:mm:ss") + '
' + + // '● ' + + // this.series.name + ':  ' + y + '
' + // } let noDataTafel = '
' + @@ -169,7 +178,14 @@ export const liveData = (params, values) => { } - +/******************************************** + * havg - Data + * + * @param params + * @param values + * @returns {{options: {plotOptions: {series: {marker: {enabled: boolean}, turboThreshold: number, animation: boolean}}, xAxis: {gridLineWidth: number, type: string, title: {text: string}, labels: {formatter: function(): (string|*)}}, legend: {layout: string, borderWidth: number, align: string, enabled: boolean}, subtitle: {align: string}, tooltip: {backgroundColor: number, valueDecimals: number, borderRadius: number, useHTML: boolean, borderWidth: number}, title: {useHTML: boolean, style: {fontSize: string}, align: string}, chart: {backgroundColor: {linearGradient: number[], stops: [[number,string],[number,string]]}, spacingTop: number, borderWidth: string, spacingLeft: number, type: string, spacingRight: number, events: {selection: function(*): void}, height: number}}, params, options2: any}} + * + ********************************************/ export const havgData = (params, values) => { let series1 = [] let series2 = [] @@ -219,37 +235,23 @@ export const havgData = (params, values) => { options.chart.resetZoomButton= { position: { align: 'left', -// verticalAlign: 'bottom', x: 20, y: 300, }, relativeTo: 'chart' } - options.tooltip.formatter = function () { - let y = Math.round(this.y * 10) / 10 - return '
' + - DateTime.fromMillis(this.x, {zone: 'utc'}).toFormat("dd.LL - HH'h'") + '
' + - '● ' + - this.series.name + ':  ' + y + '
' - } - return { options: options, params: params} -/* - - // Do PLOT 1 - let ch = Highcharts.chart('dhour', options, function (chart) { - utils.addSensorID2chart(chart, {sid: data.sid, indoor: data.indoor}, document.getElementById('dhour').offsetWidth) - }) - // Do PLOT 2 - options.series[0] = { + // Calculate to plot peaks + let options2 = JSON.parse(JSON.stringify(options)); + options2.series[0] = { name: 'Peaks', data: series2, color: utils.colors.peaks, type: 'column' } - options.title.text = 'Peaks more than ' + data.peak + ' dbA' - options.subtitle.text = 'Number of exceedances per hour
 ' - options.yAxis = { + options2.title.text = 'Peaks more than ' + params.peak + ' dbA' + options2.subtitle.text = 'Number of exceedances per hour
 ' + options2.yAxis = { title: { text: 'Counts', useHTML: true, @@ -258,16 +260,273 @@ export const havgData = (params, values) => { allowDecimals: false, gridLineColor: 'lightgray', } - options.tooltip.formatter = function () { - let y = Math.round(this.y) - return '
' + - DateTime.fromMillis(this.x, {zone: 'utc'}).toFormat("dd.LL - HH'h'") + '
' + - '● ' + - this.series.name + ':  ' + y + '
' - } - let ch1 = Highcharts.chart('dpeak', options) + return { options: options, options2: options2, params: params} + +} + +/******************************************** + * davg - Data + * + * @param params + * @param values + * @returns {{options: {plotOptions: {series: {marker: {enabled: boolean}, turboThreshold: number, animation: boolean}}, xAxis: {gridLineWidth: number, type: string, title: {text: string}, labels: {formatter: function(): (string|*)}}, legend: {layout: string, borderWidth: number, align: string, enabled: boolean}, subtitle: {align: string}, tooltip: {backgroundColor: number, valueDecimals: number, borderRadius: number, useHTML: boolean, borderWidth: number}, title: {useHTML: boolean, style: {fontSize: string}, align: string}, chart: {backgroundColor: {linearGradient: number[], stops: [[number,string],[number,string]]}, spacingTop: number, borderWidth: string, spacingLeft: number, type: string, spacingRight: number, events: {selection: function(*): void}, height: number}}, params, options2: any}} + * + ********************************************/ + + export const davgData = (params, values) => { + let series1 = [] + let series2 = [] + + // Put values into the serieses + let cnt = 0 + values.forEach((x) => { + if (x.n_AVG != -1) { + let dat = new Date(x.datetime).getTime() // retrieve the date + series1.push([dat, x.n_AVG]) + series2.push([dat, x.peakcount]) + } + }) + // Plot-Options + let options = utils.createGlobObtions() + // options.xAxis.plotBands = utils.calcWeekends(values, true) + options.xAxis.tickInterval = 24 * 3600 * 1000 + options.xAxis.title.text = 'Date' + // options.xAxis.labels = { + // formatter: function () { + // return this.axis.defaultLabelFormatter.call(this); + // } + // } + + options.chart.type = 'column' + options.chart.height = 350 + + options.yAxis = { + title: { + text: 'dbA', + useHTML: true, + }, + min: utils.noise_ymin, + tickAmount: 10, + gridLineColor: 'lightgray', + } + options.series = [ + { + name: 'Mean value LAeq', + data: series1, + color: utils.colors.eq, + type: 'column', + zIndex: 2, + }, + ] + options.plotOptions.column = { + pointWidth: 20, + groupPadding: 0.1 + } + options.title.text = 'Noise daily mean values' + options.subtitle.text = 'Daily mean values of LAeq for each full day
 ' + options.subtitle.useHTML = true + options.chart.zoomType = 'x' + options.chart.resetZoomButton = { + position: { + align: 'left', +// verticalAlign: 'bottom', + x: 20, + y: 300, + }, + relativeTo: 'chart' + } + + // Calculate to plot peaks + let options2 = JSON.parse(JSON.stringify(options)); + options2.series[0] = { + name: 'Peaks', + data: series2, + color: utils.colors.peaks, + type: 'column' + } + options2.title.text = 'Peaks more than ' + params.peak + ' dbA' + options2.subtitle.text = 'Number of exceedances per day
 ' + options2.yAxis = { + title: { + text: 'Counts', + useHTML: true, + }, + tickAmount: 10, + allowDecimals: false, + gridLineColor: 'lightgray', + } + + return {options: options, options2: options2, params: params} + +} + +/******************************************** + * dayNight - Data + * + * @param params + * @param values + * @returns {{options: {plotOptions: {series: {marker: {enabled: boolean}, turboThreshold: number, animation: boolean}}, xAxis: {gridLineWidth: number, type: string, title: {text: string}, labels: {formatter: function(): (string|*)}}, legend: {layout: string, borderWidth: number, align: string, enabled: boolean}, subtitle: {align: string}, tooltip: {backgroundColor: number, valueDecimals: number, borderRadius: number, useHTML: boolean, borderWidth: number}, title: {useHTML: boolean, style: {fontSize: string}, align: string}, chart: {backgroundColor: {linearGradient: number[], stops: [[number,string],[number,string]]}, spacingTop: number, borderWidth: string, spacingLeft: number, type: string, spacingRight: number, events: {selection: function(*): void}, height: number}}, params}} + * + ********************************************/ +export const dayNightData = (params, values) => { + + let series1 = [] + let series2 = [] + // Put values into the serieses + let cnt = 0 + values.forEach((x) => { + if (x.n_dayAVG > 0) { + let dat = new Date(x.datetime).getTime() // retrieve the date + series1.push([dat, x.n_dayAVG]) + series2.push([dat, x.n_nightAVG]) + } + }) + // Plot-Options + let options = utils.createGlobObtions() +// options.xAxis.plotBands = utils.calcWeekends(data, true) + options.xAxis.tickInterval = 24 * 3600 * 1000 + options.xAxis.title = 'Date' + // options.xAxis.labels = { + // formatter: function () { + // return this.axis.defaultLabelFormatter.call(this); + // } + // } + + options.chart.type = 'column' + options.yAxis = { + title: { + text: 'dbA', + useHTML: true, + }, + min: utils.noise_ymin, + tickAmount: 10, + gridLineColor: 'lightgray', + } + options.series = [ + { + name: 'Day', + data: series1, + color: utils.colors.eq, + type: 'column', + zIndex: 2, + }, + { + name: 'Night', + data: series2, + color: utils.colors.max, + type: 'column', + zIndex: 2, + }, + ] + options.plotOptions.series = { + animation: false + } + options.plotOptions.column = { + pointWidth: 20, + groupPadding: 0.3 + } + options.title.text = 'Noise Average values during the day and night hours' + options.subtitle.text = 'Daily mean values of LAeq from 6h00 to 22h00
Nightly mean values of LAeq from 22h00 to 6h00' + options.subtitle.useHTML = true + options.chart.zoomType = 'x' + options.chart.resetZoomButton = { + position: { + align: 'left', +// verticalAlign: 'bottom', + x: 20, + y: 300, + }, + relativeTo: 'chart' + } + return {options: options, params: params} +} + +/*********************************** + Lden - Data + * + * @param params + * @param values + * @returns {{options: {plotOptions: {series: {marker: {enabled: boolean}, turboThreshold: number, animation: boolean}}, xAxis: {gridLineWidth: number, type: string, title: {text: string}, labels: {formatter: function(): (string|*)}}, legend: {layout: string, borderWidth: number, align: string, enabled: boolean}, subtitle: {align: string}, tooltip: {backgroundColor: number, valueDecimals: number, borderRadius: number, useHTML: boolean, borderWidth: number}, title: {useHTML: boolean, style: {fontSize: string}, align: string}, chart: {backgroundColor: {linearGradient: number[], stops: [[number,string],[number,string]]}, spacingTop: number, borderWidth: string, spacingLeft: number, type: string, spacingRight: number, events: {selection: function(*): void}, height: number}}, params}} + **********************************/ +export const ldenData = (params, values) => { + + let series1 = [] + + // Put values into the series + let cnt = 0 + values.forEach((x) => { + if (x.lden != -1) { + let dat = new Date(x.datetime).getTime() // retrieve the date + series1.push([dat, x.lden]) + } + }) + // Plot-Options + let options = utils.createGlobObtions() + +// options.xAxis.plotBands = utils.calcWeekends(data, true) + options.xAxis.tickInterval = 24 * 3600 * 1000 + options.xAxis.title = 'Date' + options.xAxis.labels = { + formatter: function () { + let lbl = this.axis.defaultLabelFormatter.call(this); + this.value += 86400000; + let lbl1 = this.axis.defaultLabelFormatter.call(this); + return parseInt(lbl) + '/' + lbl1; + } + } + options.chart.type = 'column' + options.yAxis = { + title: { + text: 'dbA', + useHTML: true, + }, + min: utils.noise_ymin, + tickAmount: 10, + gridLineColor: 'lightgray', + } + options.series = [ + { + name: 'lden', + data: series1, + color: utils.colors.eq, + type: 'column', + zIndex: 2, + } + ] + options.plotOptions.series = { + animation: false + } + options.plotOptions.column = { + pointWidth: 20, + groupPadding: 0.1 + } + options.title.text = 'Noise LDEN-Index' + options.subtitle.text = 'Daily mean values of LDEN\-Index' + options.subtitle.useHTML = true + options.chart.zoomType = 'x' + options.chart.resetZoomButton = { + position: { + align: 'left', +// verticalAlign: 'bottom', + x: 20, + y: 300, + }, + relativeTo: 'chart' + } +/* options.tooltip.formatter = function () { + let d = DateTime.fromMillis(this.x, {zone: 'utc'}) + let d1 = d.plus({days: 1}) + let txt = d.toFormat('dd') + '/' + d1.toFormat('dd.LL') + return '
' + + '  ' + txt + '
' + + '● ' + + this.series.name + ':  ' + + Highcharts.numberFormat(this.y, 1) + + '
'; + } + + */ + return {options: options, params: params} } -*/ -} \ No newline at end of file diff --git a/utilities/chartoptions.js b/utilities/chartoptions.js index 60c5cfd..ef86c60 100644 --- a/utilities/chartoptions.js +++ b/utilities/chartoptions.js @@ -1,6 +1,7 @@ // Utility routine for plotting the data export const colors = {'eq': '#0000FF', 'max': '#FF0000', 'min': '#008000', 'peaks': '#DAA520'}; +export const noise_ymin = 30; export function createGlobObtions() { // Options, die für alle Plots identisch sind @@ -31,13 +32,11 @@ export function createGlobObtions() { } }, title: { -// text: 'Feinstaub über 1 Tag', align: 'left', style: {'fontSize': '25px'}, useHTML: true, }, subtitle: { -// text: 'Gemessene Werte und ' + avgTime + 'min-gleitende Mittelwerte', align: 'left', }, tooltip: { @@ -85,7 +84,7 @@ export function createGlobObtions() { } export function calcWeekends(data, isyear) { - let weekend = []; +/* let weekend = []; let oldDay = 8; for (let i = 0; i < data.length; i++) { let mom = moment(data[i].date); @@ -114,7 +113,7 @@ export function calcWeekends(data, isyear) { } } return weekend; -} +*/} export function calcDays(data, isyear) { let days = [];