"use strict"; // Request parameters const BASE_URL = "http://193.196.39.91:8080/frost-icity-tp31/v1.1/Datastreams(80)/Observations"; const BASE_URL2 = "http://193.196.39.91:8080/frost-icity-tp31-v2/v1.1/Datastreams(41)/Observations"; const PARAM_RESULT_FORMAT = "dataArray"; const PARAM_ORDER_BY = "phenomenonTime asc"; const PARAM_FILTER = "resultTime ge 2020-01-01T00:00:00.000Z and resultTime le 2020-07-01T00:00:00.000Z"; const PARAM_SELECT = "result,phenomenonTime"; /** * Draw an EMPTY chart using Apexcharts library * @param {HTMLElement} htmlElement - HTML element where chart will be drawn * @param {String} mainTitle - Main chart title * @param {String} yAxisTitle - Y-axis title * @returns {Object} - An empty chart object */ const drawEmptyLineChartAC = function ( htmlElement, mainTitle = "Main Chart Title", yAxisTitle = "y-axis title" ) { // Chart constants const CHART_HTML_ELEMENT = htmlElement; const TITLE_TEXT = mainTitle; const Y_AXIS_TITLE = yAxisTitle; const options = { series: [], chart: { type: "area", stacked: false, height: 350, zoom: { type: "x", enabled: true, autoScaleYaxis: true, }, toolbar: { autoSelected: "zoom", }, }, dataLabels: { enabled: false, }, markers: { size: 0, }, title: { text: TITLE_TEXT, align: "left", }, noData: { text: "Loading...", }, fill: { type: "gradient", gradient: { shadeIntensity: 1, inverseColors: false, opacityFrom: 0.5, opacityTo: 0, stops: [0, 90, 100], }, }, yaxis: { labels: { formatter: function (val) { return val.toFixed(0); }, forceNiceScale: true, }, title: { text: Y_AXIS_TITLE, }, }, xaxis: { type: "datetime", }, tooltip: { shared: false, y: { formatter: function (val) { return val.toFixed(2); }, }, }, }; const chart = new ApexCharts(CHART_HTML_ELEMENT, options); return chart; }; // Line chart 1 constants const chart1LineHTML = document.querySelector("#chart-apex-line"); const chart1LineTitle = "Inlet flow (Vorlauf)"; const chart1LineYAxisTitle = "Temperature (°C)"; // Draw an empty line chart const lineChartApex = drawEmptyLineChartAC( chart1LineHTML, chart1LineTitle, chart1LineYAxisTitle ); lineChartApex.render(); /** * Update an empty chart created using Apexcharts library * @param {String} chartName * @param {Array} dataArr * @returns {void} */ const updateLineChartAC = function (chartName, dataArr) { const CHART_NAME = chartName; // Update the chart lineChartApex.updateSeries([ { name: CHART_NAME, data: dataArr, }, ]); }; /** * Draw a heatmap using the ApexCharts library * ATTEMPT 1 * @param {Array} obsArray - Response from SensorThings API as array * @returns {void} */ const drawHeatMapAC1 = function (obsArray) { // Chart constants const CHART_HEATMAP_TITLE = "HeatMap Chart"; const CHART_HEATMAP_NAME_SERIES_1 = "VL-225"; // const CHART_HEATMAP_NAME_SERIES_2 = "W2"; /** * Convert SensorThings API response (an array) into an object * @returns {Object} - Chart series object */ const generateHeatMapData = function () { const series = []; obsArray.forEach(([obsTime, obsValue]) => { series.push({ x: obsTime.slice(0, -1), // remove trailing "Z" from timestamp y: obsValue, }); }); return series; }; const data = [ { name: CHART_HEATMAP_NAME_SERIES_1, data: generateHeatMapData(obsArray), }, // { // name: CHART_HEATMAP_NAME_SERIES_2, // data: generateHeatMapData(obsArray), // }, ]; data.reverse(); const colors = [ "#F3B415", "#F27036", "#663F59", "#6A6E94", "#4E88B4", "#00A7C6", "#18D8D8", "#A9D794", "#46AF78", "#A93F55", "#8C5E58", "#2176FF", "#33A1FD", "#7A918D", "#BAFF29", ]; // colors.reverse(); const options = { series: data, chart: { height: 350, type: "heatmap", }, dataLabels: { enabled: false, }, colors: colors, title: { text: CHART_HEATMAP_TITLE, }, grid: { padding: { right: 20, }, }, xaxis: { type: "datetime", }, tooltip: { shared: false, x: { formatter: function (val) { return new Date(val).toLocaleString(); }, }, y: { formatter: function (val) { return val.toFixed(2); }, }, }, plotOptions: { heatmap: { useFillColorAsStroke: true, // we need this option for the chart to be visible // distributed: true, // enableShades: false, }, }, }; const chart = new ApexCharts( document.querySelector("#chart-apex-heatmap"), options ); chart.render(); }; /** * Draw a heatmap using the ApexCharts library * ATTEMPT 2 * @param {Array} obsArray - Response from SensorThings API as array * @returns {void} */ const drawHeatMapAC2 = function (obsArray) { // Chart constants const CHART_HEATMAP_TITLE = "HeatMap Chart"; const CHART_HEATMAP_NAME_SERIES_1 = "VL-225"; /** * Convert SensorThings API response (an array) into an object * @returns {Object} - Chart series object */ const generateHeatMapData = function () { const series = []; obsArray.forEach(([obsTime, obsValue]) => { series.push({ x: obsTime.slice(0, -1), // remove trailing "Z" from timestamp y: obsValue, }); }); return series; }; const data = [ { name: CHART_HEATMAP_NAME_SERIES_1, data: generateHeatMapData(obsArray), }, // { // name: CHART_HEATMAP_NAME_SERIES_2, // data: generateHeatMapData(obsArray), // }, ]; // Constants for our data range const LOW_FROM = 65; const LOW_TO = 70; const MEDIUM_FROM = 70; const MEDIUM_TO = 75; const HIGH_FROM = 75; const HIGH_TO = 80; const EXTREME_FROM = 80; const EXTREME_TO = 85; const options = { series: data, chart: { height: 450, type: "heatmap", }, plotOptions: { heatmap: { shadeIntensity: 0.5, radius: 0, useFillColorAsStroke: true, colorScale: { ranges: [ { from: null, to: null, name: "null", color: "#525252", }, { from: LOW_FROM, to: LOW_TO, name: `${LOW_FROM}°C`, color: "#1a9641", }, { from: MEDIUM_FROM, to: MEDIUM_TO, name: `${MEDIUM_FROM}°C`, color: "#a6d96a", }, { from: HIGH_FROM, to: HIGH_TO, name: `${HIGH_FROM}°C`, color: "#fdae61", }, { from: EXTREME_FROM, to: EXTREME_TO, name: `${EXTREME_FROM}°C`, color: "#d7191c", }, ], }, }, }, dataLabels: { enabled: false, }, stroke: { width: 1, }, title: { text: CHART_HEATMAP_TITLE, }, grid: { padding: { right: 20, }, }, xaxis: { type: "datetime", // labels: { // format: "MMM", // }, }, tooltip: { shared: false, x: { formatter: function (val) { return new Date(val).toLocaleString(); }, }, y: { formatter: function (val) { if (val) { return val.toFixed(2); } else { return "null"; } }, }, }, // distributed: true, }; const chart = new ApexCharts( document.querySelector("#chart-apex-heatmap"), options ); chart.render(); }; /** * Follows "@iot.nextLink" links in SensorThingsAPI's response * Appends new results to existing results * @async * @param {Object} responsePromise - Promise object * @returns {Object} - Object containing results from all the "@iot.nextLink" links */ const followNextLink = function (responsePromise) { return responsePromise .then(function (lastSuccess) { if (lastSuccess.data["@iot.nextLink"]) { return followNextLink( axios.get(lastSuccess.data["@iot.nextLink"]) ).then(function (nextLinkSuccess) { nextLinkSuccess.data.value = lastSuccess.data.value.concat( nextLinkSuccess.data.value ); return nextLinkSuccess; }); } else { return lastSuccess; } }) .catch(function (err) { console.log(err); }); }; /////////////////////////////////////////////////////////////// function getDataReadyForSimplifyJS(pts) { var val = []; for (var i = 0, len = pts.length; i < len; i++) val.push(pts[i][1]); pts = val; let newPts = []; for (var i = 0, len = pts.length; i < len; i++) newPts.push({ x: i, y: pts[i] }); return newPts; } /////////////////////////////////////////////////////////////// function getPointIndiciesFromXYjson(pts) { let newPts = []; for (var i = 0, len = pts.length; i < len; i++) newPts.push(pts[i].x); return newPts; } /////////////////////////////////////////////////////////////// function getReducedDataFromSimplifiedData(originalData, simplified_data) { let red_data = []; let new_start = 0; for (var i = 0; i < originalData.length; i++) for (var j=new_start; j < simplified_data.length; j++){ if (i == simplified_data[j].x){ red_data.push([originalData[i][0],originalData[i][1]]); new_start = j+1; } } return red_data; } // Get "ALL" the Observations that satisfy our query var res = followNextLink( axios.get(BASE_URL, { params: { "$resultFormat": PARAM_RESULT_FORMAT, "$orderBy": PARAM_ORDER_BY, "$filter": PARAM_FILTER, "$select": PARAM_SELECT, }, }) ) .then((success) => { const successValue = success.data.value; // Array that will hold the combined observations const combinedObservations = []; successValue.forEach((dataObj) => { // Each page of results will have a dataArray that holds the observations const dataArrays = dataObj.dataArray; combinedObservations.push(...dataArrays); }); // DEBUG: Check total number of observations console.log(combinedObservations.length); // DEBUG: Print the array of observations console.log(combinedObservations); return combinedObservations; }) .catch((err) => { console.log(err); }) .then((observationArr) => { // updateLineChartAC(chart1LineTitle, observationArr); let simplified_data = simplify(getDataReadyForSimplifyJS(observationArr),2,true); let reducedData = getReducedDataFromSimplifiedData(observationArr, simplified_data); updateLineChartAC(chart1LineTitle, reducedData); // drawHeatMapAC2(observationArr); drawHeatMapAC2(reducedData); console.log(reducedData.length, observationArr.length); return reducedData; });