"use strict"; import { BASE_URL, QUERY_PARAMS_COMBINED, } from "./src_modules/baseUrlPlusQueryParams.mjs"; import { calculateVorlaufMinusRuecklaufTemperature } from "./src_modules/calculateTemperatureDiff.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 { drawColumnChartHighcharts } from "./src_modules/chartColumn.mjs"; import { showLoadingSpinner, hideLoadingSpinner, disableDrawChartButton, enableDrawChartButton, } from "./src_modules/loadingIndicator.mjs"; import { vanillaSelectBox } from "./thirdparty/vanillaSelectBox.mjs"; import { extractObservationsWithinDatesInterval, extractUniqueCalendarDatesFromTimestamp, } from "./src_modules/aggregateHelpers.mjs"; import { splitMultipleOptionsTextDelimitedBySlash, getSelectedOptionsFromAllDropDownLists, checkIfSelectedOptionsContainTemperatureDifference, deleteTemperatureDifferenceOptions, extractTemperatureDifferenceOptions, extractBuildingPlusSamplingRate, checkIfSelectedBuildingDataPointsOptionsAreValid, checkIfSelectedAggregationOptionsAreValid, getAbbreviationsForSelectedOptionsFromAllDropDownLists, } from "./src_modules/dropDownListHelpers.mjs"; import { drawHeatmapBasedOnSelectedOptions, drawScatterPlotFromChartSelection, drawLineChartBasedOnSelectedAggregationOptions, drawColumnChartBasedOnSelectedAggregationOptions, } from "./src_modules/dropDownListProcessing.mjs"; /** * Use the `vanillaDropDown` library to style the buildings & data points drop down list * * @returns {undefined} */ const styleBuildingsDataPointsDropDown = 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 aggregation type drop down list * * @returns {undefined} */ const styleAggregationDropDown = 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 sampling rate down list * * @returns {undefined} */ const styleSamplingRateDropDown = 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 chart type drop down list * * @returns {undefined} */ const styleChartTypeDropDown = 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 () { styleBuildingsDataPointsDropDown(); styleAggregationDropDown(); styleSamplingRateDropDown(); styleChartTypeDropDown(); }; /** * Callback function that draws a chart using options from the drop-down list that * have been selected by a user. * Will be run when the user clicks a button * * @async * @returns {undefined} undefined */ const drawChartUsingSelectedOptions = async function () { try { const selectedOptionsAllDropDownLists = getSelectedOptionsFromAllDropDownLists(); // 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; // Create an array of aggregation type and duration const selectedAggregationTypeDurationSplitNestedArr = splitMultipleOptionsTextDelimitedBySlash( selectedAggregationTypeDurationArr ); // Separate the aggregation type and the aggregation duration strings const [selectedAggregationTypeDurationSplitArr] = selectedAggregationTypeDurationSplitNestedArr; const [selectedAggregationType, selectedAggregationDuration] = selectedAggregationTypeDurationSplitArr; // Array of building(s) + data point(s) + sampling rate const selectedBuildingsDataPointsSamplingRateAbbrevNestedArr = getAbbreviationsForSelectedOptionsFromAllDropDownLists( selectedOptionsAllDropDownLists ); // The values of these references is either equal to `true` or an error will be thrown // We would like the errors to be thrown at this point before we begin performing any asynchronous tasks const selectedAggregationOptionsAreValid = checkIfSelectedAggregationOptionsAreValid( selectedChartTypeArr, selectedAggregationType, selectedAggregationDuration ); const selectedBuildingDataPointsOptionsAreValid = checkIfSelectedBuildingDataPointsOptionsAreValid( selectedChartTypeArr, selectedBuildingsDataPointsSamplingRateAbbrevNestedArr ); // Check whether we have dT (temperature difference), if so, delete these options, // then compute abbreviations for raw observations const selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr = checkIfSelectedOptionsContainTemperatureDifference( selectedBuildingsDataPointsSamplingRateAbbrevNestedArr ) ? deleteTemperatureDifferenceOptions( selectedBuildingsDataPointsSamplingRateAbbrevNestedArr ) : selectedBuildingsDataPointsSamplingRateAbbrevNestedArr; // Check if we have dT (temperature difference) const selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr = checkIfSelectedOptionsContainTemperatureDifference( selectedBuildingsDataPointsSamplingRateAbbrevNestedArr ) ? extractTemperatureDifferenceOptions( selectedBuildingsDataPointsSamplingRateAbbrevNestedArr ) : []; // Display the loading indicator showLoadingSpinner(); // Disable the 'draw chart' button disableDrawChartButton(); // Fetch the observations + metadata / raw observations const observationsRawPlusMetadataArr = selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr.length === 0 ? [[], []] : await getMetadataPlusObservationsFromSingleOrMultipleDatastreams( BASE_URL, QUERY_PARAMS_COMBINED, selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr ); // Fetch the observations + metadata / temperature difference (dT) const observationsTempDiffPlusMetadataArr = selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr.length === 0 ? [[], []] : await calculateVorlaufMinusRuecklaufTemperature( BASE_URL, QUERY_PARAMS_COMBINED, extractBuildingPlusSamplingRate( selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr ) ); // Extract the combined arrays for observations and metadata / raw observations const [observationsRawNestedArr, metadataTempDiffNestedArr] = observationsRawPlusMetadataArr; // Extract the combined arrays for observations and metadata / temperature difference (dT) const [observationsNestedComputedArr, metadataNestedComputedArr] = observationsTempDiffPlusMetadataArr; // Create a combined array of observations and metadata const observationsPlusMetadataCombined = [ [...observationsRawNestedArr, ...observationsNestedComputedArr], [...metadataTempDiffNestedArr, ...metadataNestedComputedArr], ]; const [observationsComboNestedArr, metadataComboNestedArr] = observationsPlusMetadataCombined; // Create formatted array(s) for metadata - used by ALL chart types const formattedMetadataNestedArr = metadataComboNestedArr.map( (metadataObj) => formatDatastreamMetadataForChart(metadataObj) ); // Extract the formatted metadata properties for the raw observations - used by ALL chart types const rawObservationsExtractedFormattedDatastreamProperties = extractPropertiesFromFormattedDatastreamMetadata( formattedMetadataNestedArr, false ); // The formatted abbreviations array is nested const [selectedBuildingsDataPointsSamplingRateAbbrevArr] = selectedBuildingsDataPointsSamplingRateAbbrevNestedArr; // Extract the formatted sampling rate string - used by ALL chart types const [, , selectedSamplingRateAbbrev] = selectedBuildingsDataPointsSamplingRateAbbrevArr; // User-specified start date and end date for aggregation - used by MULTIPLE chart types const aggregationStartDate = "2020-01-01"; const aggregationEndDate = "2020-12-31"; // 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 = observationsComboNestedFinalArr.map( (observationsArr) => extractUniqueCalendarDatesFromTimestamp(observationsArr) ); for (const selectedChartType of selectedChartTypeArr) { switch (selectedChartType) { // We are interested in raw observations ONLY case "Heatmap": if ( selectedAggregationOptionsAreValid && selectedBuildingDataPointsOptionsAreValid ) { drawHeatmapBasedOnSelectedOptions( observationsComboNestedFinalArr, rawObservationsExtractedFormattedDatastreamProperties ); } 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; 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(); } }; document.addEventListener("DOMContentLoaded", afterDocumentLoads); document .querySelector("#btn-draw-chart") .addEventListener("click", drawChartUsingSelectedOptions);