Commit 35dc06f4 authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

New function: callback function that draws chart

Function uses options from drop-down list that have been selected by a
user to populate the appropriate observations and then draw the
appropriate chart
parent 59f58680
...@@ -69,7 +69,6 @@ ...@@ -69,7 +69,6 @@
Custom JS --> Custom JS -->
<script defer type="module" src="js/appCesium.js"></script> <script defer type="module" src="js/appCesium.js"></script>
<script defer type="module" src="js/appChart.js"></script> <script defer type="module" src="js/appChart.js"></script>
<script defer type="module" src="js/dropDownList.js"></script>
</head> </head>
<body class="sb-nav-fixed"> <body class="sb-nav-fixed">
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark"> <nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
...@@ -131,6 +130,21 @@ ...@@ -131,6 +130,21 @@
<label for="droneMode">Drone View</label> <label for="droneMode">Drone View</label>
</div> </div>
<br /> --> <br /> -->
<div id="drop-down--chart-type-parent">
<span><strong>Chart type</strong></span>
<div class="nowrap">
<!-- We need the `multiple` attribute for the dropdowns even if
we do not need to support multiple selections. This seems to
be a quirk of the `vanillaSelectBox` library -->
<select id="drop-down--chart-type" multiple>
<option>Column</option>
<option>Line</option>
<option>Heatmap</option>
<option>Scatter Plot</option>
</select>
</div>
</div>
<br />
<div id="drop-down--bldg-data-point-parent"> <div id="drop-down--bldg-data-point-parent">
<span><strong>Building(s), Data Point(s)</strong></span> <span><strong>Building(s), Data Point(s)</strong></span>
<div class="nowrap"> <div class="nowrap">
...@@ -140,6 +154,9 @@ ...@@ -140,6 +154,9 @@
size="5" size="5"
> >
<!-- Note: The values of the option elements have to be unique --> <!-- Note: The values of the option elements have to be unique -->
<optgroup label="Other">
<option>Außentemp</option>
</optgroup>
<optgroup label="Bau 101"> <optgroup label="Bau 101">
<option>101/VL</option> <option>101/VL</option>
<option>101/RL</option> <option>101/RL</option>
...@@ -174,9 +191,6 @@ ...@@ -174,9 +191,6 @@
<option>225/Energie</option> <option>225/Energie</option>
<option>225/Energie_VERBR</option> <option>225/Energie_VERBR</option>
</optgroup> </optgroup>
<optgroup label="Other">
<option>Außentemp</option>
</optgroup>
</select> </select>
</div> </div>
</div> </div>
...@@ -216,21 +230,6 @@ ...@@ -216,21 +230,6 @@
</div> </div>
</div> </div>
<br /> <br />
<div id="drop-down--chart-type-parent">
<span><strong>Chart type</strong></span>
<div class="nowrap">
<!-- We need the `multiple` attribute for the dropdowns even if
we do not need to support multiple selections. This seems to
be a quirk of the `vanillaSelectBox` library -->
<select id="drop-down--chart-type" multiple>
<option>Column</option>
<option>Line</option>
<option>Heatmap</option>
<option>Scatter Plot</option>
</select>
</div>
</div>
<br />
<button id="btn-draw-chart">Draw Chart</button> <button id="btn-draw-chart">Draw Chart</button>
<!-- <span><strong>Display Options</strong></span> <!-- <span><strong>Display Options</strong></span>
<div class="nowrap"> <div class="nowrap">
......
This diff is collapsed.
...@@ -7,127 +7,139 @@ import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./fe ...@@ -7,127 +7,139 @@ import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./fe
import { extractPhenomenonNameFromDatastreamName } from "./fetchedDataProcessing.mjs"; import { extractPhenomenonNameFromDatastreamName } from "./fetchedDataProcessing.mjs";
/** /**
* Calculate the temperature difference, dT, between Vorlauf temperature [VL] and Rücklauf temperature [RL] (i.e., dT = VL - RL) * Calculate the temperature difference, dT, between Vorlauf temperature [VL] and
* Rücklauf temperature [RL] (i.e., dT = VL - RL). In addition, create synthetic metadata
* for the temperature difference
* @async * @async
* @param {String} baseUrl Base URL of the STA server * @param {String} baseUrl Base URL of the STA server
* @param {Object} urlParams The URL parameters to be sent together with the GET request * @param {Object} urlParams The URL parameters to be sent together with the GET request
* @param {String} buildingId The building ID as a string * @param {Array} buildingSamplingRateNestedArr A N*1 array (where N >= 1) containing a nested array of buildings & sampling rates as strings, i.e. [["101", "15min"]] or [["101", "15min"], ["102", "60min"]] or [["101", "15min"], ["102", "60min"], ["225", "60min"]], etc
* @param {String} samplingRate The sampling rate as a string * @returns {Promise} A promise that contains a 1*2 array (the first element is an array that contans N Observations arrays; and the second element is an array of N Datastream metadata objects) when fulfilled
* @returns {Promise} A promise that contains an array (that is made up of a temperature difference array and a metadata object) when fulfilled
*/ */
export const calculateVorlaufMinusRuecklaufTemperature = async function ( export const calculateVorlaufMinusRuecklaufTemperature = async function (
baseUrl, baseUrl,
urlParams, urlParams,
buildingId, buildingSamplingRateNestedArr
samplingRate
) { ) {
try { try {
const bldgSensorSamplingRateNestedArr = [ // Arrays to store our results
[buildingId, "vl", samplingRate], const combinedObservationsArr = [];
[buildingId, "rl", samplingRate], const combinedMetadataArr = [];
];
const buildingDataPointSamplingRateNestedTwiceArr =
const BUILDING_ID = buildingId; buildingSamplingRateNestedArr.map((bldgSmplngRate) => {
const SAMPLING_RATE = samplingRate; // The building ID is the first element, sampling rate is second element
return [
const observationsPlusMetadata = [bldgSmplngRate[0], "vl", bldgSmplngRate[1]],
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams( [bldgSmplngRate[0], "rl", bldgSmplngRate[1]],
baseUrl, ];
urlParams, });
bldgSensorSamplingRateNestedArr
// Note: We have to use a for/of loop here due to the asynchronous nature of our code
for (const bldgDataPtSamplingRateNestedArr of buildingDataPointSamplingRateNestedTwiceArr) {
// Use the first element of the nested array to extract building ID + sampling rate
// Note: we skip the second element
const [buildingId, , samplingRate] = bldgDataPtSamplingRateNestedArr[0];
const BUILDING_ID = buildingId;
const SAMPLING_RATE = samplingRate;
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
baseUrl,
urlParams,
bldgDataPtSamplingRateNestedArr
);
// Extract Vorlauf temperature, Ruecklauf temperature and metadata
const [
[vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr],
[metadataVorlauf, metadataRuecklauf],
] = observationsPlusMetadata;
// Compare the lengths of the observations arrays for VL and RL,
// delete the unique observation(s), if necessary
const [vorlaufTemperatureObsFinalArr, ruecklaufTemperatureObsFinalArr] =
vorlaufTemperatureObsArr.length === ruecklaufTemperatureObsArr.length
? [vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr]
: checkForAndDeleteUniqueObservationsFromLargerArray(
vorlaufTemperatureObsArr,
ruecklaufTemperatureObsArr
);
// Extract the temperature values
const vorlaufTemperatureValues = vorlaufTemperatureObsFinalArr.map(
(vlTempObs) => vlTempObs[1]
);
const ruecklaufTemperatureValues = ruecklaufTemperatureObsFinalArr.map(
(rlTempObs) => rlTempObs[1]
); );
// Extract Vorlauf temperature, Ruecklauf temperature and metadata // The arrays have equal length, we need only use one of them for looping
const [ // Resulting array contains the following pairs (timestamp + dT)
[vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr], const vorlaufMinusRuecklaufTemperatureObs = vorlaufTemperatureObsArr.map(
[metadataVorlauf, metadataRuecklauf], (vlTempObs, i) => {
] = observationsPlusMetadata; // Use timestamp from VL, since is equal to that of RL
const timestamp = vlTempObs[0];
// Compare the lengths of the observations arrays for VL and RL,
// delete the unique observation(s), if necessary // Case 1: One of the observation values is `null`,
const [vorlaufTemperatureObsFinalArr, ruecklaufTemperatureObsFinalArr] = // no need to calculate temperature difference
vorlaufTemperatureObsArr.length === ruecklaufTemperatureObsArr.length if (
? [vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr] vorlaufTemperatureValues[i] === null ||
: checkForAndDeleteUniqueObservationsFromLargerArray( ruecklaufTemperatureValues[i] === null
vorlaufTemperatureObsArr, ) {
ruecklaufTemperatureObsArr return [timestamp, null];
); }
// Extract the temperature values // Case 2: Neither of the observation values is `null`,
const vorlaufTemperatureValues = vorlaufTemperatureObsFinalArr.map( // calculate temperature difference
(vlTempObs) => vlTempObs[1] return [
); timestamp,
const ruecklaufTemperatureValues = ruecklaufTemperatureObsFinalArr.map( vorlaufTemperatureValues[i] - ruecklaufTemperatureValues[i],
(rlTempObs) => rlTempObs[1] ];
);
// The arrays have equal length, we need only use one of them for looping
// Resulting array contains the following pairs (timestamp + dT)
const vorlaufMinusRuecklaufTemperatureObs = vorlaufTemperatureObsArr.map(
(vlTempObs, i) => {
// Use timestamp from VL, since is equal to that of RL
const timestamp = vlTempObs[0];
// Case 1: One of the observation values is `null`,
// no need to calculate temperature difference
if (
vorlaufTemperatureValues[i] === null ||
ruecklaufTemperatureValues[i] === null
) {
return [timestamp, null];
} }
);
// Case 2: Neither of the observation values is `null`, // From Vorlauf metadata, extract `name` and `unitOfMeasurement`
// calculate temperature difference const {
return [ name: datastreamNameVorlauf,
timestamp, unitOfMeasurement: unitOfMeasurementVorlauf,
vorlaufTemperatureValues[i] - ruecklaufTemperatureValues[i], } = metadataVorlauf;
];
} // From Ruecklauf metadata, extract `name`
); const { name: datastreamNameRuecklauf } = metadataRuecklauf;
// From Vorlauf metadata, extract `name` and `unitOfMeasurement` // Extract the phenomenon names from the Datastream names
const { const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName(
name: datastreamNameVorlauf, datastreamNameVorlauf
unitOfMeasurement: unitOfMeasurementVorlauf, );
} = metadataVorlauf; const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
datastreamNameRuecklauf
// From Ruecklauf metadata, extract `name`
const { name: datastreamNameRuecklauf } = metadataRuecklauf;
// Extract the phenomenon names from the Datastream names
const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName(
datastreamNameVorlauf
);
const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
datastreamNameRuecklauf
);
// Create our custom datastream description text
// The resulting datastream description string has two `temperature` substrings;
// replace the first occurence with an empty string
const descriptionTempDifference =
`Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`.replace(
"temperature",
""
); );
// Create our custom datastream name text // Create our custom datastream description text
const nameTempDifference = `BOSCH_${BUILDING_ID} / dT Temperature difference (VL-RL) DS:${SAMPLING_RATE}`; // The resulting datastream description string has two `temperature` substrings;
// replace the first occurence with an empty string
// The datastream object that we return needs to have these property names const descriptionTempDifference =
const description = descriptionTempDifference; `Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`.replace(
const name = nameTempDifference; "temperature",
const unitOfMeasurement = unitOfMeasurementVorlauf; ""
);
return [
vorlaufMinusRuecklaufTemperatureObs, // Create our custom datastream name text
{ const nameTempDifference = `BOSCH_${BUILDING_ID} / dT Temperature difference (VL-RL) DS:${SAMPLING_RATE}`;
description,
name, // The datastream object that we return needs to have these property names
unitOfMeasurement, const description = descriptionTempDifference;
}, const name = nameTempDifference;
]; const unitOfMeasurement = unitOfMeasurementVorlauf;
// Add the observations and metadata to our arrays
combinedObservationsArr.push(vorlaufMinusRuecklaufTemperatureObs);
combinedMetadataArr.push({ description, name, unitOfMeasurement });
}
return [combinedObservationsArr, combinedMetadataArr];
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
......
"use strict";
import {
BASE_URL,
QUERY_PARAMS_COMBINED,
} from "./src_modules/baseUrlPlusQueryParams.mjs";
import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./src_modules/fetchData.mjs";
import {
formatDatastreamMetadataForChart,
extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcessing.mjs";
import {
formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts,
} from "./src_modules/chartLine.mjs";
import {
formatSensorThingsApiResponseForHeatMap,
drawHeatMapHighcharts,
} from "./src_modules/chartHeatmap.mjs";
import {
showLoadingSpinner,
hideLoadingSpinner,
} from "./src_modules/loadingIndicator.mjs";
import { vanillaSelectBox } from "./thirdparty/vanillaSelectBox.mjs";
/**
* Use the `vanillaDropDown` library to style the first level drop down list
*
* @returns {undefined}
*/
const styleLevelOneDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`; supports the selection of multiple options
new vanillaSelectBox("#drop-down--bldg-data-point", {
"disableSelectAll": true,
"maxSelect": 5,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Use the `vanillaDropDown` library to style the second level drop down list
*
* @returns {undefined}
*/
const styleLevelTwoDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--aggregation-type", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Use the `vanillaDropDown` library to style the third level drop down list
*
* @returns {undefined}
*/
const styleLevelThreeDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--sampling-rate", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Use the `vanillaDropDown` library to style the fourth level drop down list
*
* @returns {undefined}
*/
const styleLevelFourDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--chart-type", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Callback function that wraps the logic of populating the linked drop down lists.
* Will run on `DOMContentLoaded` event
*
* @returns {undefined}
*/
const afterDocumentLoads = function () {
styleLevelOneDropDown();
styleLevelTwoDropDown();
styleLevelThreeDropDown();
styleLevelFourDropDown();
};
/** /**
* Get the selected option(s) from a dropdown list * Get the selected option(s) from a dropdown list
* *
...@@ -126,7 +22,6 @@ const getSelectedOptionsFromDropDownList = function (selectorStr) { ...@@ -126,7 +22,6 @@ const getSelectedOptionsFromDropDownList = function (selectorStr) {
/** /**
* Process the selected option(s) from a buildings & data points dropdown list. * Process the selected option(s) from a buildings & data points dropdown list.
* This is currently the first dropdown list in the UI.
* *
* @param {Array} selectedOptionsArr An array of string(s) representing the value(s) of the selected `<option>` elements * @param {Array} selectedOptionsArr An array of string(s) representing the value(s) of the selected `<option>` elements
* @returns {Array} An array of string(s) representing the processed value(s) of the selected buildings & data points option(s) * @returns {Array} An array of string(s) representing the processed value(s) of the selected buildings & data points option(s)
...@@ -138,10 +33,9 @@ const processSelectionsFromBuildingDataPointOptions = function ( ...@@ -138,10 +33,9 @@ const processSelectionsFromBuildingDataPointOptions = function (
const selectedOptionsBuildingDataPointArr = []; const selectedOptionsBuildingDataPointArr = [];
selectedOptionsArr.forEach((optionStr) => { selectedOptionsArr.forEach((optionStr) => {
// Case 1: <option> element's value CONTAINS a "/" character
// We wish to create a string like this `Bau 101/VL`
if (optionStr.includes("/")) { if (optionStr.includes("/")) {
// Case 1: <option> element's value CONTAINS a "/" character
// We wish to create a string like this `Bau 101/VL`
// Split the <option> element's value into two substrings // Split the <option> element's value into two substrings
const optionsStrPartOne = optionStr.slice(0, 3); const optionsStrPartOne = optionStr.slice(0, 3);
const optionsStrPartTwo = optionStr.slice(3); const optionsStrPartTwo = optionStr.slice(3);
...@@ -153,9 +47,10 @@ const processSelectionsFromBuildingDataPointOptions = function ( ...@@ -153,9 +47,10 @@ const processSelectionsFromBuildingDataPointOptions = function (
const optionsStrNew = optionsStrPartOneNew + optionsStrPartTwo; const optionsStrNew = optionsStrPartOneNew + optionsStrPartTwo;
selectedOptionsBuildingDataPointArr.push(optionsStrNew); selectedOptionsBuildingDataPointArr.push(optionsStrNew);
} else { }
// Case 2: <option> element's value DOES NOT CONTAIN a "/" character // Case 2: <option> element's value DOES NOT CONTAIN a "/" character
// We wish to create a string like this `Other/Außentemp` // We wish to create a string like this `Other/Außentemp`
else {
selectedOptionsBuildingDataPointArr.push(`Other/${optionStr}`); selectedOptionsBuildingDataPointArr.push(`Other/${optionStr}`);
} }
}); });
...@@ -166,11 +61,23 @@ const processSelectionsFromBuildingDataPointOptions = function ( ...@@ -166,11 +61,23 @@ const processSelectionsFromBuildingDataPointOptions = function (
/** /**
* Split an option element's value (a string) using a forward slash character ("/") as the delimiter * Split an option element's value (a string) using a forward slash character ("/") as the delimiter
* *
* @param {String} selectedOptionsStr A string representing the value of the selected `<option>` element
* @returns {String} Resulting strings after splitting
*/
const splitOptionsTextDelimitedBySlash = function (selectedOptionsStr) {
return selectedOptionsStr.split("/");
};
/**
* Split an array of option element's values (strings) which have a forward slash character ("/") as the delimiter
*
* @param {Array} selectedOptionsArr An array of string(s) representing the value(s) of the selected `<option>` elements * @param {Array} selectedOptionsArr An array of string(s) representing the value(s) of the selected `<option>` elements
* @returns {Array} An array made up of resulting strings after splitting * @returns {Array} An array made up of resulting strings after splitting
*/ */
const splitOptionsTextDelimitedBySlash = function (selectedOptionsArr) { const splitMultipleOptionsTextDelimitedBySlash = function (selectedOptionsArr) {
return selectedOptionsArr.map((selectedOption) => selectedOption.split("/")); return selectedOptionsArr.map((selectedOption) =>
splitOptionsTextDelimitedBySlash(selectedOption)
);
}; };
/** /**
...@@ -185,7 +92,9 @@ const getSelectedOptionsFromAllDropDownLists = function () { ...@@ -185,7 +92,9 @@ const getSelectedOptionsFromAllDropDownLists = function () {
// Separate the building ID from the data point // Separate the building ID from the data point
const selectedBuildingDataPointOptionsSplitArr = const selectedBuildingDataPointOptionsSplitArr =
splitOptionsTextDelimitedBySlash(selectedBuildingDataPointOptionsArr); splitMultipleOptionsTextDelimitedBySlash(
selectedBuildingDataPointOptionsArr
);
const selectedAggregationOptionsArr = getSelectedOptionsFromDropDownList( const selectedAggregationOptionsArr = getSelectedOptionsFromDropDownList(
"#drop-down--aggregation-type" "#drop-down--aggregation-type"
...@@ -200,7 +109,6 @@ const getSelectedOptionsFromAllDropDownLists = function () { ...@@ -200,7 +109,6 @@ const getSelectedOptionsFromAllDropDownLists = function () {
); );
// Ensure that all the options have at least one selection // Ensure that all the options have at least one selection
if ( if (
selectedBuildingDataPointOptionsSplitArr.length === 0 || selectedBuildingDataPointOptionsSplitArr.length === 0 ||
selectedAggregationOptionsArr.length === 0 || selectedAggregationOptionsArr.length === 0 ||
...@@ -217,6 +125,177 @@ const getSelectedOptionsFromAllDropDownLists = function () { ...@@ -217,6 +125,177 @@ const getSelectedOptionsFromAllDropDownLists = function () {
]; ];
}; };
/**
* Check whether the abbreviated buildings + data points + sampling rate strings
* contain the temperature difference [dT] between Vorlauf temperature [VL] and
* Rücklauf temperature [RL] (i.e., dT = VL - RL). Unlike all the other data points,
* this data point is computed in a separate step
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of strings representing the abbreviated building + data point + sampling rate values
* @returns {Boolean} true if the selected options contain the string `dT`, false otherwise
*/
const checkIfSelectedOptionsContainTemperatureDifference = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Create a flattened copy of our input array,
// then check if it contains the string `dT`
return buildingDataPointSamplingRateAbbrevArr.flat().includes("dT");
};
/**
* Get the index(es) of the the abbreviated buildings + data points + sampling rate string(s)
* that contains the temperature difference (dT)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains an integer(s) whose value(s) are the index(es) of the abbreviated building + data point + sampling rate string(s) containing the temperature difference (dT)
*/
const getIndexesOfTemperatureDifferenceOptions = function (
buildingDataPointSamplingRateAbbrevArr
) {
// An array to store the final result
const foundIndexesArr = [];
// Use the index, i, provided by `forEach` array method
buildingDataPointSamplingRateAbbrevArr.forEach(
(bldgDataPntSamplingRateAbbrvArr, i) => {
if (bldgDataPntSamplingRateAbbrvArr.includes("dT")) {
foundIndexesArr.push(i);
}
}
);
return foundIndexesArr;
};
/**
* Delete the abbreviated building + data point + sampling rate string(s) that contains the temperature difference (dT)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
*/
const deleteTemperatureDifferenceOptions = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Calculate the index(es) that we wish to delete
const foundIndexesArr = getIndexesOfTemperatureDifferenceOptions(
buildingDataPointSamplingRateAbbrevArr
);
// Delete the index(es) of `dT`, modifies the array in place
// Note: The resulting array is sparse
foundIndexesArr.forEach(
(foundIndex) => delete buildingDataPointSamplingRateAbbrevArr[foundIndex]
);
// Array to store our final result
const buildingDataPointFinalArr = [];
// Remove the empty sub array(s) that makes entire array sparse
// Note: `empty` does not mean `undefined` or `null`
buildingDataPointSamplingRateAbbrevArr.forEach(
(bldgDataPntSmplingRateAbbrvArr) => {
if (typeof bldgDataPntSmplingRateAbbrvArr === "object") {
buildingDataPointFinalArr.push(bldgDataPntSmplingRateAbbrvArr);
}
}
);
return buildingDataPointFinalArr;
};
/**
* Extract the abbreviated building + data point + sampling rate string(s) that contains the temperature difference (dT)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
*/
const extractTemperatureDifferenceOptions = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Array to store final result
const temperatureDifferenceOptionsAbbrevArr = [];
// Calculate the index(es) that we wish to extract
const foundIndexesArr = getIndexesOfTemperatureDifferenceOptions(
buildingDataPointSamplingRateAbbrevArr
);
foundIndexesArr.forEach((foundIndex) => {
// Extracted array for a single found index
const bldgDataPntSamplingRateAbbrvArr =
buildingDataPointSamplingRateAbbrevArr[foundIndex];
// Extract the building and sampling rate strings
// Note: we have ignored the second element
// const [bldgAbbrv, , samplingRateAbbrv] = bldgDataPntSamplingRateAbbrvArr;
// Create a new array that contains two elements,
// the building and sampling rate abbreviated strings
// const bldgSamplingRateAbbrvArr = [bldgAbbrv, samplingRateAbbrv];
temperatureDifferenceOptionsAbbrevArr.push(bldgDataPntSamplingRateAbbrvArr);
});
return temperatureDifferenceOptionsAbbrevArr;
};
/**
* Extract the abbreviated building + sampling rate string(s) for use in calculating the temperature difference (dT = VL - RL)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains nested array(s) made up of abbreviated building + sampling rate string(s)
*/
const extractBuildingPlusSamplingRate = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Array to store final result
const temperatureDifferenceOptionsAbbrevArr = [];
// Calculate the index(es) that we wish to extract
const foundIndexesArr = getIndexesOfTemperatureDifferenceOptions(
buildingDataPointSamplingRateAbbrevArr
);
foundIndexesArr.forEach((foundIndex) => {
// Extracted array for a single found index
const bldgDataPntSamplingRateAbbrvArr =
buildingDataPointSamplingRateAbbrevArr[foundIndex];
// Extract the building and sampling rate strings
// Note: we have ignored the second element
const [bldgAbbrv, , samplingRateAbbrv] = bldgDataPntSamplingRateAbbrvArr;
// Create a new array that contains two elements,
// the building and sampling rate abbreviated strings
const bldgSamplingRateAbbrvArr = [bldgAbbrv, samplingRateAbbrv];
temperatureDifferenceOptionsAbbrevArr.push(bldgSamplingRateAbbrvArr);
});
return temperatureDifferenceOptionsAbbrevArr;
};
/**
* Determine if a chart requires raw observations instead of aggregated observations
*
* @param {String} selectedAggregationType The selected aggregation type
* @param {String} selectedAggregationDuration The selected aggregation duration
* @returns {Boolean} true if the chart requires raw observations, false if not
*/
const checkIfChartRequiresRawObservations = function (
selectedAggregationType,
selectedAggregationDuration
) {
if (
selectedAggregationType === "None (raw data)" &&
selectedAggregationDuration === undefined
) {
return true;
} else {
return false;
}
};
/** /**
* Get the abbreviated form of building IDs, phenomenon names and sensor sampling rates * Get the abbreviated form of building IDs, phenomenon names and sensor sampling rates
* @param {String} buildingFullForm A string representation of the full form of a building ID * @param {String} buildingFullForm A string representation of the full form of a building ID
...@@ -239,17 +318,18 @@ const getBuildingSensorSamplingRateAbbreviation = function ( ...@@ -239,17 +318,18 @@ const getBuildingSensorSamplingRateAbbreviation = function (
"Bau 225": "225", "Bau 225": "225",
"Other": "weather_station_521", "Other": "weather_station_521",
}, },
phenomenon: { phenomenon: {
VL: "vl", VL: "vl",
RL: "rl", RL: "rl",
dT: "dT", dT: "dT",
Durchfluss: "flow", Durchfluss: "flow",
Leistung: "power", Leistung: "power",
Energie: "energy", Energie: "energy",
Energie_VERBR: "energy_verb", Energie_VERBR: "energy_verb",
Außentemp: "outside_temp", Außentemp: "outside_temp",
}, },
samplingRate: { samplingRate: {
"15 min": "15min", "15 min": "15min",
"60 min": "60min", "60 min": "60min",
...@@ -330,88 +410,13 @@ const getAbbreviationsForSelectedOptionsFromAllDropDownLists = function ( ...@@ -330,88 +410,13 @@ const getAbbreviationsForSelectedOptionsFromAllDropDownLists = function (
); );
}; };
/** export {
* Callback function for chart selection using drop down list splitMultipleOptionsTextDelimitedBySlash,
* @returns {undefined} getSelectedOptionsFromAllDropDownLists,
*/ checkIfSelectedOptionsContainTemperatureDifference,
const selectChartTypeFromDropDown = async function () { deleteTemperatureDifferenceOptions,
try { extractTemperatureDifferenceOptions,
const selectedOptions = getSelectedOptionsFromDropDownLists(); extractBuildingPlusSamplingRate,
checkIfChartRequiresRawObservations,
if (selectedOptions === undefined) return; getAbbreviationsForSelectedOptionsFromAllDropDownLists,
const selectedOptionsAbbreviationsArr =
getBuildingSensorSamplingRateAbbreviation(...selectedOptions);
const selectedChartType = document.querySelector(
"#drop-down--chart-type"
).value;
if (selectedChartType === "--Select--") return;
// Display the loading indicator
showLoadingSpinner();
// The `getMetadataPlusObservationsFromSingleOrMultipleDatastreams` function expects a nested array structure
const abbreviationsNestedArr = [selectedOptionsAbbreviationsArr];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
abbreviationsNestedArr
);
// Extract the combined arrays for observations and metadata
const [observationsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// Create formatted array(s) for observations - line chart
const formattedObsLineChartNestedArr = observationsNestedArr.map(
(observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
);
// Create formatted array(s) for observations - heatmap
const formattedObsHeatMapNestedArr = observationsNestedArr.map(
(observationsArr) =>
formatSensorThingsApiResponseForHeatMap(observationsArr)
);
// Create formatted array(s) for metadata - same for both chart types
const formattedMetadataArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataArr,
false
);
if (selectedChartType === "Line") {
drawLineChartHighcharts(
formattedObsLineChartNestedArr,
extractedFormattedDatastreamProperties
);
} else if (selectedChartType === "Heatmap") {
// First need to extract the formatted observations from the nested array
// Heatmap only needs one set of formatted observation values
drawHeatMapHighcharts(
...formattedObsHeatMapNestedArr,
extractedFormattedDatastreamProperties
);
}
} catch (err) {
console.error(err);
} finally {
// Hide the loading indicator
hideLoadingSpinner();
}
}; };
document.addEventListener("DOMContentLoaded", afterDocumentLoads);
document
.querySelector("#drop-down--chart-type")
.addEventListener("change", selectChartTypeFromDropDown);
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment