From 05ac1b569ea5145661d74ab2c72ebffb34ecd4e9 Mon Sep 17 00:00:00 2001 From: Pithon Kabiro <pithon.kabiro@hft-stuttgart.de> Date: Thu, 30 Sep 2021 14:05:00 +0200 Subject: [PATCH] Make further edits to markup for drop-down lists --- index.html | 33 +++++-- public/js/dropDownList.js | 195 +++++++++++++++++++++++++++++++++++--- 2 files changed, 206 insertions(+), 22 deletions(-) diff --git a/index.html b/index.html index 5997c90..d51f644 100644 --- a/index.html +++ b/index.html @@ -186,7 +186,10 @@ ><strong>Aggregation (Type, Duration)</strong></span > <div class="nowrap"> - <select id="drop-down--aggregation-type"> + <!-- 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--aggregation-type" multiple> <option>None (raw data)</option> <option>Sum/Daily</option> <option>Sum/Monthly</option> @@ -203,7 +206,10 @@ <div id="drop-down--sampling-rate-parent"> <span><strong>Sampling rate</strong></span> <div class="nowrap"> - <select id="drop-down--sampling-rate"> + <!-- 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--sampling-rate" multiple> <option>15 min</option> <option>60 min</option> </select> @@ -213,7 +219,10 @@ <div id="drop-down--chart-type-parent"> <span><strong>Chart type</strong></span> <div class="nowrap"> - <select id="drop-down--chart-type"> + <!-- 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> @@ -249,7 +258,7 @@ <div class="card mb-4"> <div class="card-header"> <i class="fas fa-chart-line mr-1"></i> - Line Chart Example + Line Chart </div> <div class="card-body"> <div id="chart-line" width="100%" height="40"></div> @@ -260,7 +269,7 @@ <div class="card mb-4"> <div class="card-header"> <i class="fas fa-chart-area mr-1"></i> - Area Chart Example + Heatmap </div> <div class="card-body"> <div id="chart-heatmap" width="100%" height="40"></div> @@ -274,7 +283,7 @@ <div class="card-header"> <!-- No free scatter plot icon available; use this instead --> <i class="fas fa-braille mr-1"></i> - Scatter Plot Example + Scatter Plot </div> <div class="card-body"> <div id="chart-scatter-plot" width="100%" height="40"></div> @@ -285,7 +294,7 @@ <div class="card mb-4"> <div class="card-header"> <i class="far fa-chart-bar mr-1"></i> - Bar Chart Example + Column Chart </div> <div class="card-body"> <div id="chart-column" width="100%" height="40"></div> @@ -302,9 +311,15 @@ > <div class="text-muted">Copyright © HfT Stuttgart 2021</div> <div> - <a href="#">Privacy Policy</a> + <a href="https://www.hft-stuttgart.de/impressum" target="_blank" + >Impressum</a + > · - <a href="#">Terms & Conditions</a> + <a + href="https://www.hft-stuttgart.de/datenschutz" + target="_blank" + >Datenschutz</a + > </div> </div> </div> diff --git a/public/js/dropDownList.js b/public/js/dropDownList.js index 14cde18..b3526de 100644 --- a/public/js/dropDownList.js +++ b/public/js/dropDownList.js @@ -52,7 +52,10 @@ const styleLevelOneDropDown = function () { const styleLevelTwoDropDown = function () { // Create our dropdown list using `vanillaSelectBox` new vanillaSelectBox("#drop-down--aggregation-type", { + "disableSelectAll": true, + "maxSelect": 1, "placeHolder": "--Select--", + "search": false, }); }; @@ -64,7 +67,10 @@ const styleLevelTwoDropDown = function () { const styleLevelThreeDropDown = function () { // Create our dropdown list using `vanillaSelectBox` new vanillaSelectBox("#drop-down--sampling-rate", { + "disableSelectAll": true, + "maxSelect": 1, "placeHolder": "--Select--", + "search": false, }); }; @@ -76,7 +82,10 @@ const styleLevelThreeDropDown = function () { const styleLevelFourDropDown = function () { // Create our dropdown list using `vanillaSelectBox` new vanillaSelectBox("#drop-down--chart-type", { + "disableSelectAll": true, + "maxSelect": 1, "placeHolder": "--Select--", + "search": false, }); }; @@ -94,24 +103,118 @@ const afterDocumentLoads = function () { }; /** - * Get the values from the currently selected options in the linked drop dpwn lists - * @returns {Array} An array containing the values of the selected options + * Get the selected option(s) from a dropdown list + * + * @param {String} selectorStr A CSS selector string representing the dropdown list + * @returns {Array} An array of string(s) representing the value(s) of the selected `<option>` elements + */ +const getSelectedOptionsFromDropDownList = function (selectorStr) { + // Array to store our final result + const selectedOptionsArr = []; + + // Select all the matching <option> elements as a NodeList + const optionElements = document.querySelectorAll(`${selectorStr} option`); + + optionElements.forEach((optionEl) => { + if (optionEl.selected) { + selectedOptionsArr.push(optionEl.value); + } + }); + + return selectedOptionsArr; +}; + +/** + * 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 + * @returns {Array} An array of string(s) representing the processed value(s) of the selected buildings & data points option(s) + */ +const processSelectionsFromBuildingDataPointOptions = function ( + selectedOptionsArr +) { + // Array to store our final result + const selectedOptionsBuildingDataPointArr = []; + + selectedOptionsArr.forEach((optionStr) => { + 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 + const optionsStrPartOne = optionStr.slice(0, 3); + const optionsStrPartTwo = optionStr.slice(3); + + // Create a new string for the first substring + const optionsStrPartOneNew = `Bau ${optionsStrPartOne}`; + + // Create a new combined string + const optionsStrNew = optionsStrPartOneNew + optionsStrPartTwo; + + selectedOptionsBuildingDataPointArr.push(optionsStrNew); + } else { + // Case 2: <option> element's value DOES NOT CONTAIN a "/" character + // We wish to create a string like this `Other/Außentemp` + selectedOptionsBuildingDataPointArr.push(`Other/${optionStr}`); + } + }); + + return selectedOptionsBuildingDataPointArr; +}; + +/** + * Split an option element's value (a string) using a forward slash character ("/") as the delimiter + * + * @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 + */ +const splitOptionsTextDelimitedBySlash = function (selectedOptionsArr) { + return selectedOptionsArr.map((selectedOption) => selectedOption.split("/")); +}; + +/** + * Get the values from the currently selected options in ALL the drop down lists + * @returns {Array} An array containing four arrays, where each array contains the values of the selected options */ -const getSelectedOptionsFromDropDownLists = function () { - const selectedBuilding = document.querySelector("#drop-down--bldg").value; - const selectedSensor = document.querySelector("#drop-down--sensor").value; - const selectedSamplingRate = document.querySelector( +const getSelectedOptionsFromAllDropDownLists = function () { + const selectedBuildingDataPointOptionsArr = + processSelectionsFromBuildingDataPointOptions( + getSelectedOptionsFromDropDownList("#drop-down--bldg-data-point") + ); + + // Separate the building ID from the data point + const selectedBuildingDataPointOptionsSplitArr = + splitOptionsTextDelimitedBySlash(selectedBuildingDataPointOptionsArr); + + const selectedAggregationOptionsArr = getSelectedOptionsFromDropDownList( + "#drop-down--aggregation-type" + ); + + const selectedSamplingRateArr = getSelectedOptionsFromDropDownList( "#drop-down--sampling-rate" - ).value; + ); + + const selectedChartTypeArr = getSelectedOptionsFromDropDownList( + "#drop-down--chart-type" + ); + + // Ensure that all the options have at least one selection if ( - selectedBuilding === "--Select--" || - selectedSensor === "" || - selectedSamplingRate === "" + selectedBuildingDataPointOptionsSplitArr.length === 0 || + selectedAggregationOptionsArr.length === 0 || + selectedSamplingRateArr.length === 0 || + selectedChartTypeArr.length === 0 ) return; - return [selectedBuilding, selectedSensor, selectedSamplingRate]; + return [ + selectedBuildingDataPointOptionsSplitArr, + selectedAggregationOptionsArr, + selectedSamplingRateArr, + selectedChartTypeArr, + ]; }; /** @@ -134,14 +237,18 @@ const getBuildingSensorSamplingRateAbbreviation = function ( "Bau 112": "112, 118", "Bau 125": "125", "Bau 225": "225", + "Other": "weather_station_521", }, phenomenon: { - Vorlauftemperatur: "vl", - Rücklauftemperatur: "rl", + VL: "vl", + RL: "rl", + dT: "dT", + Durchfluss: "flow", Leistung: "power", Energie: "energy", Energie_VERBR: "energy_verb", + Außentemp: "outside_temp", }, samplingRate: { "15 min": "15min", @@ -149,6 +256,29 @@ const getBuildingSensorSamplingRateAbbreviation = function ( }, }; + if ( + fullFormToAbbreviationMapping["buildings"]?.[buildingFullForm] === undefined + ) + throw new Error( + "The provided building ID is not valid or is not supported by this function" + ); + + if ( + fullFormToAbbreviationMapping["phenomenon"]?.[phenomenonFullForm] === + undefined + ) + throw new Error( + "The provided data point is not valid or is not supported by this function" + ); + + if ( + fullFormToAbbreviationMapping["samplingRate"]?.[samplingRateFullForm] === + undefined + ) + throw new Error( + "The provided sampling rate is not valid or is not supported by this function" + ); + const buildingAbbrev = fullFormToAbbreviationMapping["buildings"]?.[buildingFullForm]; @@ -161,6 +291,45 @@ const getBuildingSensorSamplingRateAbbreviation = function ( return [buildingAbbrev, phenomenonAbbrev, samplingRateAbbrev]; }; +/** + * Get the abbreviated form for the currently selected options in ALL the drop down lists + * + * @param {Array} allSelectedOptionsArr An array containing four arrays, where each array contains the values of the selected options + * @returns {Array} An array which contains one or more nested arrays of abbreviations of building(s), data point(s) and sampling rate(s) + */ +const getAbbreviationsForSelectedOptionsFromAllDropDownLists = function ( + allSelectedOptionsArr +) { + // Note: The sampling rate array is the third array, therefore we skip one element + const [selectedBuildingDataPointOptionsSplitArr, , selectedSamplingRateArr] = + allSelectedOptionsArr; + + // The building is the first element + const selectedBuildingsArr = selectedBuildingDataPointOptionsSplitArr.map( + (selectedBuildingDataPoint) => selectedBuildingDataPoint[0] + ); + + // The data point is the second element + const selectedDataPointsArr = selectedBuildingDataPointOptionsSplitArr.map( + (selectedBuildingDataPoint) => selectedBuildingDataPoint[1] + ); + + // Assume that the buildings and data points arrays have equal length + // use one of the arrays for looping + if (selectedBuildingsArr.length !== selectedDataPointsArr.length) + throw new Error( + "The buildings array and data points array have different lengths" + ); + + return selectedBuildingsArr.map((selectedBuilding, i) => + getBuildingSensorSamplingRateAbbreviation( + selectedBuilding, + selectedDataPointsArr[i], + ...selectedSamplingRateArr + ) + ); +}; + /** * Callback function for chart selection using drop down list * @returns {undefined} -- GitLab