Commit 559e7982 authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

Rewrite multiple 'if' statements using 'switch'

parent 04eb3a11
......@@ -24,6 +24,8 @@ import { drawColumnChartHighcharts } from "./src_modules/chartColumn.mjs";
import {
showLoadingSpinner,
hideLoadingSpinner,
disableDrawChartButton,
enableDrawChartButton,
} from "./src_modules/loadingIndicator.mjs";
import { vanillaSelectBox } from "./thirdparty/vanillaSelectBox.mjs";
......@@ -138,7 +140,7 @@ const drawChartUsingSelectedOptions = async function () {
const selectedOptionsAllDropDownLists =
getSelectedOptionsFromAllDropDownLists();
// Note: The aggregation type + duration and chart type are the first and
// Note: The chart type amd aggregation type + duration are the first and
// third elements respectively, we have ignored the second and fourth elements
const [selectedChartTypeArr, , selectedAggregationTypeDurationArr] =
selectedOptionsAllDropDownLists;
......@@ -178,71 +180,74 @@ const drawChartUsingSelectedOptions = async function () {
);
// Create copies of the arrays of building(s) + data point(s) + sampling rate
const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr = [
const selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr = [
...selectedBuildingsDataPointsSamplingRateAbbrevNestedArr,
];
const selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr = [
const selectedBuildingsDataPointsSamplingRateAbbrevTempDiffCopyArr = [
...selectedBuildingsDataPointsSamplingRateAbbrevNestedArr,
];
// Check if we have non-computed
const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr =
// Check if we have raw observations
const selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr =
checkIfSelectedOptionsContainTemperatureDifference(
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr
selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr
)
? deleteTemperatureDifferenceOptions(
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr
selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr
)
: selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr;
: selectedBuildingsDataPointsSamplingRateAbbrevRawObsCopyArr;
// Check if we have computed / dT
const selectedBuildingsDataPointsSamplingRateAbbrevComputedArr =
// Check if we have dT (temperature difference)
const selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr =
checkIfSelectedOptionsContainTemperatureDifference(
selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr
selectedBuildingsDataPointsSamplingRateAbbrevTempDiffCopyArr
)
? extractTemperatureDifferenceOptions(
selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr
selectedBuildingsDataPointsSamplingRateAbbrevTempDiffCopyArr
)
: [];
// Display the loading indicator
showLoadingSpinner();
// Fetch the observations + metadata / non-computed
const observationsPlusMetadataNonComputedArr =
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr.length === 0
// Disable the 'draw chart' button
disableDrawChartButton();
// Fetch the observations + metadata / raw observations
const observationsRawPlusMetadataArr =
selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr.length === 0
? [[], []]
: await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr
selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr
);
// Fetch the observations + metadata / computed (dT)
const observationsPlusMetadataComputedArr =
selectedBuildingsDataPointsSamplingRateAbbrevComputedArr.length === 0
// Fetch the observations + metadata / temperature difference (dT)
const observationsTempDiffPlusMetadataArr =
selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr.length === 0
? [[], []]
: await calculateVorlaufMinusRuecklaufTemperature(
BASE_URL,
QUERY_PARAMS_COMBINED,
extractBuildingPlusSamplingRate(
selectedBuildingsDataPointsSamplingRateAbbrevComputedArr
selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr
)
);
// Extract the combined arrays for observations and metadata / non-computed
const [observationsNestedNonComputedArr, metadataNestedNonComputedArr] =
observationsPlusMetadataNonComputedArr;
// Extract the combined arrays for observations and metadata / raw observations
const [observationsRawNestedArr, metadataTempDiffNestedArr] =
observationsRawPlusMetadataArr;
// Extract the combined arrays for observations and metadata / computed (dT)
// Extract the combined arrays for observations and metadata / temperature difference (dT)
const [observationsNestedComputedArr, metadataNestedComputedArr] =
observationsPlusMetadataComputedArr;
observationsTempDiffPlusMetadataArr;
// Create a combined array of observations and metadata
const observationsPlusMetadataCombined = [
[...observationsNestedNonComputedArr, ...observationsNestedComputedArr],
[...metadataNestedNonComputedArr, ...metadataNestedComputedArr],
[...observationsRawNestedArr, ...observationsNestedComputedArr],
[...metadataTempDiffNestedArr, ...metadataNestedComputedArr],
];
const [observationsComboNestedArr, metadataComboNestedArr] =
......@@ -253,8 +258,8 @@ const drawChartUsingSelectedOptions = async function () {
(metadataObj) => formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties - used by ALL chart types
const extractedFormattedDatastreamProperties =
// Extract the formatted metadata properties for the raw observations - used by ALL chart types
const rawObservationsExtractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
false
......@@ -272,111 +277,125 @@ const drawChartUsingSelectedOptions = async function () {
const aggregationStartDate = "2020-01-01";
const aggregationEndDate = "2020-12-31";
// Extract observations within the user-specified start and end date - used by MULTIPLE chart types
const observationsAggregationNestedArr = observationsComboNestedArr.map(
(obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
aggregationStartDate,
aggregationEndDate
)
);
// Create final array of observations- used by MULTIPLE chart types
// If we are performing aggregation, it was envisioned that the user would
// select observations that fall within a start and end date
const observationsComboNestedFinalArr =
selectedAggregationType === "None (raw data)"
? observationsComboNestedArr
: observationsComboNestedArr.map((observationsArr) =>
extractObservationsWithinDatesInterval(
observationsArr,
selectedSamplingRateAbbrev,
aggregationStartDate,
aggregationEndDate
)
);
// Unique calendar dates - used by MULTIPLE chart types
const uniqueCalendarDatesNestedArr = observationsAggregationNestedArr.map(
const uniqueCalendarDatesNestedArr = observationsComboNestedFinalArr.map(
(observationsArr) =>
extractUniqueCalendarDatesFromTimestamp(observationsArr)
);
for (const selectedChartType of selectedChartTypeArr) {
if (selectedChartType === "Heatmap") {
// We are interested in raw observations
if (
selectedAggregationOptionsAreValid &&
selectedBuildingDataPointsOptionsAreValid
) {
drawHeatmapBasedOnSelectedOptions(
observationsComboNestedArr,
extractedFormattedDatastreamProperties
);
}
}
if (selectedChartType === "Scatter Plot") {
// We are interested in raw observations
if (
selectedAggregationOptionsAreValid &&
selectedBuildingDataPointsOptionsAreValid
) {
drawScatterPlotFromChartSelection(
observationsComboNestedArr,
extractedFormattedDatastreamProperties
);
}
}
if (selectedChartType === "Line") {
// We are interested in raw observations or aggregated observations
// Raw observations
if (selectedAggregationType === "None (raw data)") {
// Create formatted array(s) for observations
const formattedRawObservationsLineChartNestedArr =
observationsComboNestedArr.map((observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
switch (selectedChartType) {
// We are interested in raw observations ONLY
case "Heatmap":
if (
selectedAggregationOptionsAreValid &&
selectedBuildingDataPointsOptionsAreValid
) {
drawHeatmapBasedOnSelectedOptions(
observationsComboNestedFinalArr,
rawObservationsExtractedFormattedDatastreamProperties
);
drawLineChartHighcharts(
formattedRawObservationsLineChartNestedArr,
extractedFormattedDatastreamProperties
);
}
// Aggregated observations
else {
drawLineChartBasedOnSelectedAggregationOptions(
selectedAggregationType,
selectedAggregationDuration,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
);
}
}
if (selectedChartType === "Column") {
// We are interested in raw observations or aggregated observations
// Raw observations
if (selectedAggregationType === "None (raw data)") {
// Create formatted array(s) for observations
const formattedRawObservationsColumnChartNestedArr =
observationsComboNestedArr.map((observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
}
break;
// We are interested in raw observations ONLY
case "Scatter Plot":
if (
selectedAggregationOptionsAreValid &&
selectedBuildingDataPointsOptionsAreValid
) {
drawScatterPlotFromChartSelection(
observationsComboNestedFinalArr,
rawObservationsExtractedFormattedDatastreamProperties
);
}
break;
// We are interested in BOTH raw observations and aggregated observations
case "Line":
// Raw observations
if (selectedAggregationType === "None (raw data)") {
// Create formatted array(s) for observations
const formattedRawObservationsLineChartNestedArr =
observationsComboNestedFinalArr.map((observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(
observationsArr
)
);
drawLineChartHighcharts(
formattedRawObservationsLineChartNestedArr,
rawObservationsExtractedFormattedDatastreamProperties
);
}
// Aggregated observations
else {
drawLineChartBasedOnSelectedAggregationOptions(
selectedAggregationType,
selectedAggregationDuration,
observationsComboNestedFinalArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
);
}
break;
// We are interested in BOTH raw observations and aggregated observations
case "Column":
// Raw observations
if (selectedAggregationType === "None (raw data)") {
// Create formatted array(s) for observations
const formattedRawObservationsColumnChartNestedArr =
observationsComboNestedFinalArr.map((observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(
observationsArr
)
);
drawColumnChartHighcharts(
formattedRawObservationsColumnChartNestedArr,
rawObservationsExtractedFormattedDatastreamProperties
);
}
// Aggregated observations
else {
drawColumnChartBasedOnSelectedAggregationOptions(
selectedAggregationType,
selectedAggregationDuration,
observationsComboNestedFinalArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
);
}
break;
drawColumnChartHighcharts(
formattedRawObservationsColumnChartNestedArr,
extractedFormattedDatastreamProperties
);
}
// Aggregated observations
else {
drawColumnChartBasedOnSelectedAggregationOptions(
selectedAggregationType,
selectedAggregationDuration,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
);
}
default:
throw new Error("None of the chart type options were selected");
}
}
} catch (err) {
console.error(err);
} finally {
// Enable the 'draw chart' button
enableDrawChartButton();
// Hide the loading indicator
hideLoadingSpinner();
}
......
......@@ -5,6 +5,16 @@ import {
extractObservationValuesWithinMonthInterval,
} from "./aggregateHelpers.mjs";
/**
* Remove `null` observation values from an array of observation values
*
* @param {Array} obsValuesArr An array of observation values
* @returns {Array} An array with `null` observation values removed
*/
const filterOutNullObservationValues = function (obsValuesArr) {
return obsValuesArr.filter((obs) => obs !== null);
};
/**
* Calculate the minimum observation values that fall within a time interval delimited by a start date and end date
* @param {Array} obsValuesForDaysIntervalArr An array of observation values that fall within our time interval
......@@ -13,7 +23,10 @@ import {
const calculateMinimumObservationValuesWithinDatesInterval = function (
obsValuesForDaysIntervalArr
) {
return Math.min(...obsValuesForDaysIntervalArr);
// If the observation value is `null`, skip the calculation
return obsValuesForDaysIntervalArr.reduce((previousValue, obsValue) =>
obsValue === null ? null : Math.min(previousValue, obsValue)
);
};
/**
......@@ -24,7 +37,10 @@ const calculateMinimumObservationValuesWithinDatesInterval = function (
const calculateMaximumObservationValuesWithinDatesInterval = function (
obsValuesForDaysIntervalArr
) {
return Math.max(...obsValuesForDaysIntervalArr);
// If the observation value is `null`, skip the calculation
return obsValuesForDaysIntervalArr.reduce((previousValue, obsValue) =>
obsValue === null ? null : Math.max(previousValue, obsValue)
);
};
/**
......@@ -35,8 +51,10 @@ const calculateMaximumObservationValuesWithinDatesInterval = function (
const calculateSumOfObservationValuesWithinDatesInterval = function (
obsValuesForDaysIntervalArr
) {
return obsValuesForDaysIntervalArr.reduce(
(accumulator, obsValue) => accumulator + obsValue
// Remove the `null` observation values before calculating the sum
return filterOutNullObservationValues(obsValuesForDaysIntervalArr).reduce(
(previousValue, obsValue) => previousValue + obsValue,
0
);
};
......@@ -48,10 +66,11 @@ const calculateSumOfObservationValuesWithinDatesInterval = function (
const calculateAverageOfObservationValuesWithinDatesInterval = function (
obsValuesForDaysIntervalArr
) {
// The observation values array should only include non-`null` values
return (
calculateSumOfObservationValuesWithinDatesInterval(
obsValuesForDaysIntervalArr
) / obsValuesForDaysIntervalArr.length
) / filterOutNullObservationValues(obsValuesForDaysIntervalArr).length
);
};
......@@ -63,7 +82,10 @@ const calculateAverageOfObservationValuesWithinDatesInterval = function (
const calculateMinimumObservationValuesWithinMonthInterval = function (
obsValuesForMonthIntervalArr
) {
return Math.min(...obsValuesForMonthIntervalArr);
// If the observation value is `null`, skip the calculation
return obsValuesForMonthIntervalArr.reduce((previousValue, obsValue) =>
obsValue === null ? null : Math.min(previousValue, obsValue)
);
};
/**
......@@ -74,7 +96,10 @@ const calculateMinimumObservationValuesWithinMonthInterval = function (
const calculateMaximumObservationValuesWithinMonthInterval = function (
obsValuesForMonthIntervalArr
) {
return Math.max(...obsValuesForMonthIntervalArr);
// If the observation value is `null`, skip the calculation
return obsValuesForMonthIntervalArr.reduce((previousValue, obsValue) =>
obsValue === null ? null : Math.max(previousValue, obsValue)
);
};
/**
......@@ -85,8 +110,10 @@ const calculateMaximumObservationValuesWithinMonthInterval = function (
const calculateSumOfObservationValuesWithinMonthInterval = function (
obsValuesForMonthIntervalArr
) {
return obsValuesForMonthIntervalArr.reduce(
(accumulator, obsValue) => accumulator + obsValue
// Remove the `null` observation values before calculating the sum
return filterOutNullObservationValues(obsValuesForMonthIntervalArr).reduce(
(previousValue, obsValue) => previousValue + obsValue,
0
);
};
......@@ -98,10 +125,11 @@ const calculateSumOfObservationValuesWithinMonthInterval = function (
const calculateAverageOfObservationValuesWithinMonthInterval = function (
obsValuesForMonthIntervalArr
) {
// The observation values array should only include non-`null` values
return (
calculateSumOfObservationValuesWithinMonthInterval(
obsValuesForMonthIntervalArr
) / obsValuesForMonthIntervalArr.length
) / filterOutNullObservationValues(obsValuesForMonthIntervalArr).length
);
};
......
......@@ -131,10 +131,12 @@ const drawColumnChartHighcharts = function (
title: {
text: textChartTitle,
"align": "center",
},
subtitle: {
text: textChartSubtitle,
"align": "center",
},
xAxis: {
......@@ -143,7 +145,6 @@ const drawColumnChartHighcharts = function (
},
yAxis: {
min: 0,
title: {
text: `${phenomenonName} [${unitOfMeasurementSymbol}]`,
},
......@@ -155,10 +156,10 @@ const drawColumnChartHighcharts = function (
// this.x -- common for all points
// this.points -- an array containing properties for each series
// Note that our `reduce` method is in this format:
// ((accumulator, currentValue, currentIndex) => {...}, initialValue)
// ((previousValue, currentValue, currentIndex) => {...}, initialValue)
return this.points.reduce(
(accumulator, point, i) =>
`${accumulator} <br/> <span style="color:${point.color}">${
(previousValue, point, i) =>
`${previousValue} <br/> <span style="color:${point.color}">${
point.series.name
}</span>: <b>${point.y.toFixed(2)} ${
unitOfMeasurementSymbolsArr[i]
......
......@@ -48,7 +48,8 @@ const calculateMinMaxValuesForHeatmapColorAxis = function (
const maxValue = Math.trunc(Math.max(...obsValueArr));
// Calculate the closest multiple of 5
const minObsValue = minValue - (minValue % 5);
const minObsValue =
minValue > 0 ? minValue - (minValue % 5) : minValue + (minValue % 5);
const maxObsValue = maxValue + (5 - (maxValue % 5));
return { minObsValue, maxObsValue };
......@@ -98,13 +99,13 @@ const drawHeatMapHighcharts = function (
title: {
text: TEXT_CHART_TITLE,
align: "left",
align: "center",
x: 40,
},
subtitle: {
text: TEXT_CHART_SUBTITLE,
align: "left",
align: "center",
x: 40,
},
......
......@@ -134,12 +134,12 @@ const drawLineChartHighcharts = function (
title: {
text: textChartTitle,
"align": "left",
"align": "center",
},
subtitle: {
text: textChartSubtitle,
align: "left",
align: "center",
},
tooltip: {
......
......@@ -231,12 +231,12 @@ const drawScatterPlotHighcharts = function (
title: {
text: CHART_TITLE,
"align": "left",
"align": "center",
},
subtitle: {
text: CHART_SUBTITLE,
"align": "left",
"align": "center",
},
xAxis: {
......
"use strict";
/**
* Get the selected option(s) from a dropdown list
*
......
"use strict";
import { drawLineChartHighcharts } from "./chartLine.mjs";
import {
......
......@@ -2,7 +2,7 @@
/**
* Show a loading indicator at the start of an async task. The indicator consists of a spinner and a transluscent mask placed on top of page elements
* @returns {undefined}
* @returns {undefined} undefined
*/
const showLoadingSpinner = function () {
const loadingIndicatorMask = document.querySelector("#loadingIndicator");
......@@ -14,7 +14,7 @@ const showLoadingSpinner = function () {
/**
* Hide the loading indicator after completion of the async tasks
* @returns {undefined}
* @returns {undefined} undefined
*/
const hideLoadingSpinner = function () {
const loadingIndicatorMask = document.querySelector("#loadingIndicator");
......@@ -24,4 +24,27 @@ const hideLoadingSpinner = function () {
loadingIconSpinner.style.display = "none";
};
export { showLoadingSpinner, hideLoadingSpinner };
/**
* Disable the button used to trigger the drawing of charts
*
* @returns {undefined} undefined
*/
const disableDrawChartButton = function () {
document.querySelector("#btn-draw-chart").disabled = true;
};
/**
* Enable the button used to trigger the drawing of charts
*
* @returns {undefined} undefined
*/
const enableDrawChartButton = function () {
document.querySelector("#btn-draw-chart").disabled = false;
};
export {
showLoadingSpinner,
hideLoadingSpinner,
disableDrawChartButton,
enableDrawChartButton,
};
/*!
* Start Bootstrap - SB Admin v6.0.2 (https://startbootstrap.com/template/sb-admin)
* Copyright 2013-2020 Start Bootstrap
* Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-sb-admin/blob/master/LICENSE)
*/
(function($) {
"use strict";
* Start Bootstrap - SB Admin v7.0.3 (https://startbootstrap.com/template/sb-admin)
* Copyright 2013-2021 Start Bootstrap
* Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-sb-admin/blob/master/LICENSE)
*/
//
// Scripts
//
// Add active state to sidbar nav links
var path = window.location.href; // because the 'href' property of the DOM element is the absolute path
$("#layoutSidenav_nav .sb-sidenav a.nav-link").each(function() {
if (this.href === path) {
$(this).addClass("active");
}
});
// Toggle the side navigation
$("#sidebarToggle").on("click", function(e) {
e.preventDefault();
$("body").toggleClass("sb-sidenav-toggled");
window.addEventListener("DOMContentLoaded", (event) => {
// Toggle the side navigation
const sidebarToggle = document.body.querySelector("#sidebarToggle");
if (sidebarToggle) {
// Uncomment Below to persist sidebar toggle between refreshes
// if (localStorage.getItem('sb|sidebar-toggle') === 'true') {
// document.body.classList.toggle('sb-sidenav-toggled');
// }
sidebarToggle.addEventListener("click", (event) => {
event.preventDefault();
document.body.classList.toggle("sb-sidenav-toggled");
localStorage.setItem(
"sb|sidebar-toggle",
document.body.classList.contains("sb-sidenav-toggled")
);
});
})(jQuery);
}
});
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