Commit 0c48cb36 authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

Check selected options validity before fetch data

Confirm that the selected drop-dowwn options are valid before fetching
the observations
parent 6838b0dd
...@@ -40,7 +40,8 @@ import { ...@@ -40,7 +40,8 @@ import {
deleteTemperatureDifferenceOptions, deleteTemperatureDifferenceOptions,
extractTemperatureDifferenceOptions, extractTemperatureDifferenceOptions,
extractBuildingPlusSamplingRate, extractBuildingPlusSamplingRate,
checkIfChartRequiresRawObservations, checkIfSelectedBuildingDataPointsOptionsAreValid,
checkIfSelectedAggregationOptionsAreValid,
getAbbreviationsForSelectedOptionsFromAllDropDownLists, getAbbreviationsForSelectedOptionsFromAllDropDownLists,
} from "./src_modules/dropDownListHelpers.mjs"; } from "./src_modules/dropDownListHelpers.mjs";
...@@ -137,9 +138,9 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -137,9 +138,9 @@ const drawChartUsingSelectedOptions = async function () {
const selectedOptionsAllDropDownLists = const selectedOptionsAllDropDownLists =
getSelectedOptionsFromAllDropDownLists(); getSelectedOptionsFromAllDropDownLists();
// Note: The aggregation type + duration and chart type are the second and // Note: The aggregation type + duration and chart type are the first and
// fourth elements respectively, we have ignored the first and third elements // third elements respectively, we have ignored the second and fourth elements
const [, selectedAggregationTypeDurationArr, , selectedChartTypeArr] = const [selectedChartTypeArr, , selectedAggregationTypeDurationArr] =
selectedOptionsAllDropDownLists; selectedOptionsAllDropDownLists;
// Create an array of aggregation type and duration // Create an array of aggregation type and duration
...@@ -152,41 +153,56 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -152,41 +153,56 @@ const drawChartUsingSelectedOptions = async function () {
const [selectedAggregationTypeDurationSplitArr] = const [selectedAggregationTypeDurationSplitArr] =
selectedAggregationTypeDurationSplitNestedArr; selectedAggregationTypeDurationSplitNestedArr;
const [selectedAggregationTypeArr, selectedAggregationDuration] = const [selectedAggregationType, selectedAggregationDuration] =
selectedAggregationTypeDurationSplitArr; selectedAggregationTypeDurationSplitArr;
// Array of building(s) + data point(s) + sampling rate // Array of building(s) + data point(s) + sampling rate
const selectedBuildingsDataPointsSamplingRateAbbrev = const selectedBuildingsDataPointsSamplingRateAbbrevNestedArr =
getAbbreviationsForSelectedOptionsFromAllDropDownLists( getAbbreviationsForSelectedOptionsFromAllDropDownLists(
selectedOptionsAllDropDownLists 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
);
// Create copies of the arrays of building(s) + data point(s) + sampling rate // Create copies of the arrays of building(s) + data point(s) + sampling rate
const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy = [ const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr = [
...selectedBuildingsDataPointsSamplingRateAbbrev, ...selectedBuildingsDataPointsSamplingRateAbbrevNestedArr,
]; ];
const selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy = [ const selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr = [
...selectedBuildingsDataPointsSamplingRateAbbrev, ...selectedBuildingsDataPointsSamplingRateAbbrevNestedArr,
]; ];
// Check if we have non-computed // Check if we have non-computed
const selectedBuildingsDataPointsSamplingRateAbbrevNonComputed = const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr =
checkIfSelectedOptionsContainTemperatureDifference( checkIfSelectedOptionsContainTemperatureDifference(
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr
) )
? deleteTemperatureDifferenceOptions( ? deleteTemperatureDifferenceOptions(
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr
) )
: selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy; : selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopyArr;
// Check if we have computed / dT // Check if we have computed / dT
const selectedBuildingsDataPointsSamplingRateAbbrevComputed = const selectedBuildingsDataPointsSamplingRateAbbrevComputedArr =
checkIfSelectedOptionsContainTemperatureDifference( checkIfSelectedOptionsContainTemperatureDifference(
selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr
) )
? extractTemperatureDifferenceOptions( ? extractTemperatureDifferenceOptions(
selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy selectedBuildingsDataPointsSamplingRateAbbrevComputedCopyArr
) )
: []; : [];
...@@ -194,34 +210,34 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -194,34 +210,34 @@ const drawChartUsingSelectedOptions = async function () {
showLoadingSpinner(); showLoadingSpinner();
// Fetch the observations + metadata / non-computed // Fetch the observations + metadata / non-computed
const observationsPlusMetadataNonComputed = const observationsPlusMetadataNonComputedArr =
selectedBuildingsDataPointsSamplingRateAbbrevNonComputed.length === 0 selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr.length === 0
? [[], []] ? [[], []]
: await getMetadataPlusObservationsFromSingleOrMultipleDatastreams( : await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL, BASE_URL,
QUERY_PARAMS_COMBINED, QUERY_PARAMS_COMBINED,
selectedBuildingsDataPointsSamplingRateAbbrevNonComputed selectedBuildingsDataPointsSamplingRateAbbrevNonComputedArr
); );
// Fetch the observations + metadata / computed (dT) // Fetch the observations + metadata / computed (dT)
const observationsPlusMetadataComputed = const observationsPlusMetadataComputedArr =
selectedBuildingsDataPointsSamplingRateAbbrevComputed.length === 0 selectedBuildingsDataPointsSamplingRateAbbrevComputedArr.length === 0
? [[], []] ? [[], []]
: await calculateVorlaufMinusRuecklaufTemperature( : await calculateVorlaufMinusRuecklaufTemperature(
BASE_URL, BASE_URL,
QUERY_PARAMS_COMBINED, QUERY_PARAMS_COMBINED,
extractBuildingPlusSamplingRate( extractBuildingPlusSamplingRate(
selectedBuildingsDataPointsSamplingRateAbbrevComputed selectedBuildingsDataPointsSamplingRateAbbrevComputedArr
) )
); );
// Extract the combined arrays for observations and metadata / non-computed // Extract the combined arrays for observations and metadata / non-computed
const [observationsNestedNonComputedArr, metadataNestedNonComputedArr] = const [observationsNestedNonComputedArr, metadataNestedNonComputedArr] =
observationsPlusMetadataNonComputed; observationsPlusMetadataNonComputedArr;
// Extract the combined arrays for observations and metadata / computed (dT) // Extract the combined arrays for observations and metadata / computed (dT)
const [observationsNestedComputedArr, metadataNestedComputedArr] = const [observationsNestedComputedArr, metadataNestedComputedArr] =
observationsPlusMetadataComputed; observationsPlusMetadataComputedArr;
// Create a combined array of observations and metadata // Create a combined array of observations and metadata
const observationsPlusMetadataCombined = [ const observationsPlusMetadataCombined = [
...@@ -246,7 +262,7 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -246,7 +262,7 @@ const drawChartUsingSelectedOptions = async function () {
// The formatted abbreviations array is nested // The formatted abbreviations array is nested
const [selectedBuildingsDataPointsSamplingRateAbbrevArr] = const [selectedBuildingsDataPointsSamplingRateAbbrevArr] =
selectedBuildingsDataPointsSamplingRateAbbrev; selectedBuildingsDataPointsSamplingRateAbbrevNestedArr;
// Extract the formatted sampling rate string - used by ALL chart types // Extract the formatted sampling rate string - used by ALL chart types
const [, , selectedSamplingRateAbbrev] = const [, , selectedSamplingRateAbbrev] =
...@@ -273,50 +289,38 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -273,50 +289,38 @@ const drawChartUsingSelectedOptions = async function () {
extractUniqueCalendarDatesFromTimestamp(observationsArr) extractUniqueCalendarDatesFromTimestamp(observationsArr)
); );
selectedChartTypeArr.forEach((selectedChartType) => { for (const selectedChartType of selectedChartTypeArr) {
if (selectedChartType === "Heatmap") { if (selectedChartType === "Heatmap") {
// We are interested in raw observations // We are interested in raw observations
if ( if (
checkIfChartRequiresRawObservations( selectedAggregationOptionsAreValid &&
selectedAggregationTypeArr, selectedBuildingDataPointsOptionsAreValid
selectedAggregationDuration
)
) { ) {
drawHeatmapBasedOnSelectedOptions( drawHeatmapBasedOnSelectedOptions(
selectedBuildingsDataPointsSamplingRateAbbrev,
observationsComboNestedArr, observationsComboNestedArr,
extractedFormattedDatastreamProperties extractedFormattedDatastreamProperties
); );
} else {
throw new Error(
"This type of chart (Heatmap) does not support aggregated results"
);
} }
} }
if (selectedChartType === "Scatter Plot") { if (selectedChartType === "Scatter Plot") {
// We are interested in raw observations // We are interested in raw observations
if ( if (
checkIfChartRequiresRawObservations( selectedAggregationOptionsAreValid &&
selectedAggregationTypeArr, selectedBuildingDataPointsOptionsAreValid
selectedAggregationDuration
)
) { ) {
drawScatterPlotFromChartSelection( drawScatterPlotFromChartSelection(
selectedBuildingsDataPointsSamplingRateAbbrev,
observationsComboNestedArr, observationsComboNestedArr,
extractedFormattedDatastreamProperties extractedFormattedDatastreamProperties
); );
} else {
throw new Error(
"This type of chart (Scatter Plot) does not support aggregated results"
);
} }
} }
if (selectedChartType === "Line") { if (selectedChartType === "Line") {
// We are interested in raw observations or aggregated observations // We are interested in raw observations or aggregated observations
// Raw observations // Raw observations
if (selectedAggregationTypeArr === "None (raw data)") { if (selectedAggregationType === "None (raw data)") {
// Create formatted array(s) for observations // Create formatted array(s) for observations
const formattedRawObservationsLineChartNestedArr = const formattedRawObservationsLineChartNestedArr =
observationsComboNestedArr.map((observationsArr) => observationsComboNestedArr.map((observationsArr) =>
...@@ -331,7 +335,7 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -331,7 +335,7 @@ const drawChartUsingSelectedOptions = async function () {
// Aggregated observations // Aggregated observations
else { else {
drawLineChartBasedOnSelectedAggregationOptions( drawLineChartBasedOnSelectedAggregationOptions(
selectedAggregationTypeArr, selectedAggregationType,
selectedAggregationDuration, selectedAggregationDuration,
observationsAggregationNestedArr, observationsAggregationNestedArr,
selectedSamplingRateAbbrev, selectedSamplingRateAbbrev,
...@@ -340,11 +344,12 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -340,11 +344,12 @@ const drawChartUsingSelectedOptions = async function () {
); );
} }
} }
if (selectedChartType === "Column") { if (selectedChartType === "Column") {
// We are interested in raw observations or aggregated observations // We are interested in raw observations or aggregated observations
// Raw observations // Raw observations
if (selectedAggregationTypeArr === "None (raw data)") { if (selectedAggregationType === "None (raw data)") {
// Create formatted array(s) for observations // Create formatted array(s) for observations
const formattedRawObservationsColumnChartNestedArr = const formattedRawObservationsColumnChartNestedArr =
observationsComboNestedArr.map((observationsArr) => observationsComboNestedArr.map((observationsArr) =>
...@@ -359,7 +364,7 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -359,7 +364,7 @@ const drawChartUsingSelectedOptions = async function () {
// Aggregated observations // Aggregated observations
else { else {
drawColumnChartBasedOnSelectedAggregationOptions( drawColumnChartBasedOnSelectedAggregationOptions(
selectedAggregationTypeArr, selectedAggregationType,
selectedAggregationDuration, selectedAggregationDuration,
observationsAggregationNestedArr, observationsAggregationNestedArr,
selectedSamplingRateAbbrev, selectedSamplingRateAbbrev,
...@@ -368,7 +373,7 @@ const drawChartUsingSelectedOptions = async function () { ...@@ -368,7 +373,7 @@ const drawChartUsingSelectedOptions = async function () {
); );
} }
} }
}); }
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} finally { } finally {
......
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
import { import {
chartExportOptions, chartExportOptions,
createCombinedTextDelimitedByComma,
createFullTitleForLineOrColumnChart, createFullTitleForLineOrColumnChart,
createSubtitleForChart,
createTooltipDateString, createTooltipDateString,
extractSamplingRateFromDatastreamName,
} from "./chartHelpers.mjs"; } from "./chartHelpers.mjs";
/** /**
...@@ -122,9 +121,7 @@ const drawColumnChartHighcharts = function ( ...@@ -122,9 +121,7 @@ const drawColumnChartHighcharts = function (
aggregationType aggregationType
); );
const textChartSubtitle = `Sampling rate(s): ${createCombinedTextDelimitedByComma( const textChartSubtitle = createSubtitleForChart(datastreamNamesArr);
extractSamplingRateFromDatastreamName(datastreamNamesArr)
)}`;
Highcharts.chart("chart-column", { Highcharts.chart("chart-column", {
chart: { chart: {
......
"use strict"; "use strict";
import { chartExportOptions } from "./chartHelpers.mjs"; import {
chartExportOptions,
createTitleForHeatmap,
createSubtitleForHeatmap,
} from "./chartHelpers.mjs";
/** /**
* Format the response from SensorThings API to make it suitable for use in a heatmap * Format the response from SensorThings API to make it suitable for use in a heatmap
...@@ -73,6 +77,10 @@ const drawHeatMapHighcharts = function ( ...@@ -73,6 +77,10 @@ const drawHeatMapHighcharts = function (
const [PHENOMENON_NAME] = phenomenonNamesArr; const [PHENOMENON_NAME] = phenomenonNamesArr;
const [PHENOMENON_SYMBOL] = unitOfMeasurementSymbolsArr; const [PHENOMENON_SYMBOL] = unitOfMeasurementSymbolsArr;
const TEXT_CHART_TITLE = createTitleForHeatmap(phenomenonNamesArr);
const TEXT_CHART_SUBTITLE = createSubtitleForHeatmap(datastreamNamesArr);
const { const {
minObsValue: MINIMUM_VALUE_COLOR_AXIS, minObsValue: MINIMUM_VALUE_COLOR_AXIS,
maxObsValue: MAXIMUM_VALUE_COLOR_AXIS, maxObsValue: MAXIMUM_VALUE_COLOR_AXIS,
...@@ -89,13 +97,13 @@ const drawHeatMapHighcharts = function ( ...@@ -89,13 +97,13 @@ const drawHeatMapHighcharts = function (
}, },
title: { title: {
text: DATASTREAM_DESCRIPTION, text: TEXT_CHART_TITLE,
align: "left", align: "left",
x: 40, x: 40,
}, },
subtitle: { subtitle: {
text: DATASTREAM_NAME, text: TEXT_CHART_SUBTITLE,
align: "left", align: "left",
x: 40, x: 40,
}, },
......
...@@ -224,6 +224,34 @@ const createCombinedTextDelimitedByComma = function (metadataPropertiesArr) { ...@@ -224,6 +224,34 @@ const createCombinedTextDelimitedByComma = function (metadataPropertiesArr) {
return metadataPropertiesArr.join(", "); return metadataPropertiesArr.join(", ");
}; };
/**
* Extracts the sampling rate substring from a datastream name string
* @param {Array} datastreamNamesArr An array of datastream name(s)
* @returns {Array} An array containing the sampling rate substring(s)
*/
const extractSamplingRateFromDatastreamName = function (datastreamNamesArr) {
// First split the Datastream name string based on a single space (" ").
// The sampling rate string is the last word in the resulting string.
// We then split the resulting string using the ':' character.
// Our interest is also in the last word in the resulting string
return datastreamNamesArr.map((datastreamName) =>
datastreamName.split(" ").pop().split(":").pop()
);
};
/**
* Extract the building ID substring from a datastream name string
*
* @param {Array} datastreamNamesArr An array of datastream name(s)
* @returns {Array} An array containing the building ID substring(s)
*/
const extractBuildingIdFromDatastreamName = function (datastreamNamesArr) {
// The building ID string is the first word in the Datastream name string
return datastreamNamesArr.map((datastreamName) =>
datastreamName.split(" ").shift()
);
};
/** /**
* Create a partial string for a line chart or column chart title * Create a partial string for a line chart or column chart title
* @param {String} aggregationInterval The aggregation interval as a string, either "daily" or "monthly" * @param {String} aggregationInterval The aggregation interval as a string, either "daily" or "monthly"
...@@ -245,7 +273,7 @@ const createPartialTitleForLineOrColumnChart = function ( ...@@ -245,7 +273,7 @@ const createPartialTitleForLineOrColumnChart = function (
/** /**
* Create a full string for a line chart or column chart title * Create a full string for a line chart or column chart title
* @param {Array} datastreamNamesArr An array of datastream names as strings * @param {Array} phenomenonNamesArr An array of phenomenon names as strings
* @param {String} aggregationInterval The aggregation interval as a string, either "daily" or "monthly" * @param {String} aggregationInterval The aggregation interval as a string, either "daily" or "monthly"
* @param {String} aggregationType The aggregation type as a string, either "sum" or "average" * @param {String} aggregationType The aggregation type as a string, either "sum" or "average"
* @returns {String} Full string for chart title * @returns {String} Full string for chart title
...@@ -269,6 +297,54 @@ const createFullTitleForLineOrColumnChart = function ( ...@@ -269,6 +297,54 @@ const createFullTitleForLineOrColumnChart = function (
)}: ${createCombinedTextDelimitedByComma(phenomenonNamesArr)}`; )}: ${createCombinedTextDelimitedByComma(phenomenonNamesArr)}`;
}; };
/**
* Create a title for a heatmap
*
* @param {Array} phenomenonNamesArr An array of phenomenon names as strings
* @returns {String} A string that represents the heatmap title
*/
const createTitleForHeatmap = function (phenomenonNamesArr) {
return createCombinedTextDelimitedByComma(phenomenonNamesArr);
};
/**
* Create a subtitle for the following charts: column chart, line chart and scatter plot
*
* @param {Array} datastreamNamesArr An array of datastream name(s)
* @returns {String} A subtitle string
*/
const createSubtitleForChart = function (datastreamNamesArr) {
// Case 1: We only have one sampling rate string
if (datastreamNamesArr.length === 1) {
return `Sampling rate: ${createCombinedTextDelimitedByComma(
extractSamplingRateFromDatastreamName(datastreamNamesArr)
)}`;
}
// Case 2: We have more than one sampling rate string
else if (datastreamNamesArr.length > 1) {
return `Sampling rate(s): ${createCombinedTextDelimitedByComma(
extractSamplingRateFromDatastreamName(datastreamNamesArr)
)} respectively`;
}
};
/**
* Create a subtitle for a heatmap which is different from the subtitles used for the other
* types of charts, i.e. column charts, line charts and scatter plots
*
* @param {Array} datastreamNamesArr An array of datastream name(s)
* @returns {String} A subtitle string
*/
const createSubtitleForHeatmap = function (datastreamNamesArr) {
// Note: the `datastreamNamesArr` here contains only one element
// We use the `createCombinedTextDelimitedByComma` function to "spread" the resulting arrays
return `Building, Sampling rate: ${createCombinedTextDelimitedByComma(
extractBuildingIdFromDatastreamName(datastreamNamesArr)
)}, ${createCombinedTextDelimitedByComma(
extractSamplingRateFromDatastreamName(datastreamNamesArr)
)}`;
};
/** /**
* Creates a date string that is used in a shared tooltip for a line or column chart * Creates a date string that is used in a shared tooltip for a line or column chart
* @param {Number} pointXAxisValue The x-axis value (Unix timestamp) which is common for a set of data points * @param {Number} pointXAxisValue The x-axis value (Unix timestamp) which is common for a set of data points
...@@ -286,18 +362,6 @@ const createTooltipDateString = function ( ...@@ -286,18 +362,6 @@ const createTooltipDateString = function (
return `${Highcharts.dateFormat("%b %Y", pointXAxisValue)}`; return `${Highcharts.dateFormat("%b %Y", pointXAxisValue)}`;
}; };
/**
* Extracts the sampling rate substring from a datastream name string
* @param {Array} datastreamNamesArr An array of datastream name(s)
* @returns {Array} An array containing the sampling rate substring(s)
*/
const extractSamplingRateFromDatastreamName = function (datastreamNamesArr) {
// The sampling rate string is the last word in the Datastream name string
return datastreamNamesArr.map((datastreamName) =>
datastreamName.split(" ").pop()
);
};
/** /**
* Remove the transparency (alpha channel) from a color * Remove the transparency (alpha channel) from a color
* @param {String} rgbaColor A color expressed in RGBA format * @param {String} rgbaColor A color expressed in RGBA format
...@@ -313,8 +377,10 @@ export { ...@@ -313,8 +377,10 @@ export {
createCombinedTextDelimitedByAmpersand, createCombinedTextDelimitedByAmpersand,
createCombinedTextDelimitedByComma, createCombinedTextDelimitedByComma,
createFullTitleForLineOrColumnChart, createFullTitleForLineOrColumnChart,
createTitleForHeatmap,
createSubtitleForChart,
createSubtitleForHeatmap,
createTooltipDateString, createTooltipDateString,
convertHexColorToRGBColor, convertHexColorToRGBColor,
extractSamplingRateFromDatastreamName,
removeTransparencyFromColor, removeTransparencyFromColor,
}; };
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
import { import {
chartExportOptions, chartExportOptions,
createFullTitleForLineOrColumnChart, createFullTitleForLineOrColumnChart,
createSubtitleForChart,
createTooltipDateString, createTooltipDateString,
extractSamplingRateFromDatastreamName,
} from "./chartHelpers.mjs"; } from "./chartHelpers.mjs";
/** /**
...@@ -114,9 +114,7 @@ const drawLineChartHighcharts = function ( ...@@ -114,9 +114,7 @@ const drawLineChartHighcharts = function (
aggregationType aggregationType
); );
const textChartSubtitle = `Sampling rate(s): ${createCombinedTextForLineChartTitles( const textChartSubtitle = createSubtitleForChart(datastreamNamesArr);
extractSamplingRateFromDatastreamName(datastreamNamesArr)
)}`;
// Create the array of series options object(s) // Create the array of series options object(s)
const seriesOptionsArr = createSeriesOptionsForLineChart( const seriesOptionsArr = createSeriesOptionsForLineChart(
......
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
convertHexColorToRGBColor, convertHexColorToRGBColor,
createCombinedTextDelimitedByAmpersand, createCombinedTextDelimitedByAmpersand,
createCombinedTextDelimitedByComma, createCombinedTextDelimitedByComma,
extractSamplingRateFromDatastreamName, createSubtitleForChart,
removeTransparencyFromColor, removeTransparencyFromColor,
} from "./chartHelpers.mjs"; } from "./chartHelpers.mjs";
...@@ -200,9 +200,7 @@ const drawScatterPlotHighcharts = function ( ...@@ -200,9 +200,7 @@ const drawScatterPlotHighcharts = function (
const CHART_TITLE = const CHART_TITLE =
createCombinedTextForScatterPlotTitles(phenomenonNamesArr); createCombinedTextForScatterPlotTitles(phenomenonNamesArr);
const CHART_SUBTITLE = `Sampling rate(s): ${createCombinedTextDelimitedByComma( const CHART_SUBTITLE = createSubtitleForChart(datastreamNamesArr);
extractSamplingRateFromDatastreamName(datastreamNamesArr)
)}`;
const X_AXIS_TITLE = createXAxisTitleTextScatterPlot( const X_AXIS_TITLE = createXAxisTitleTextScatterPlot(
phenomenonNamesArr, phenomenonNamesArr,
......
...@@ -109,19 +109,23 @@ const getSelectedOptionsFromAllDropDownLists = function () { ...@@ -109,19 +109,23 @@ 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 (selectedChartTypeArr.length === 0)
selectedBuildingDataPointOptionsSplitArr.length === 0 || throw new Error("Please ensure that the chart type is selected");
selectedAggregationOptionsArr.length === 0 ||
selectedSamplingRateArr.length === 0 || if (selectedBuildingDataPointOptionsSplitArr.length === 0)
selectedChartTypeArr.length === 0 throw new Error("Please ensure that at least one data point is selected");
)
return; if (selectedSamplingRateArr.length === 0)
throw new Error("Please ensure that the aggregation type is selected");
if (selectedSamplingRateArr.length === 0)
throw new Error("Please ensure that the sampling rate is selected");
return [ return [
selectedChartTypeArr,
selectedBuildingDataPointOptionsSplitArr, selectedBuildingDataPointOptionsSplitArr,
selectedAggregationOptionsArr, selectedAggregationOptionsArr,
selectedSamplingRateArr, selectedSamplingRateArr,
selectedChartTypeArr,
]; ];
}; };
...@@ -296,6 +300,82 @@ const checkIfChartRequiresRawObservations = function ( ...@@ -296,6 +300,82 @@ const checkIfChartRequiresRawObservations = function (
} }
}; };
/**
* Check if the selected building(s) + data point(s) options are valid for
* drawing either a heatmp or scatter plot. If these options are
* invalid, throw an error
*
* @param {Array} selectedChartTypeArr An array of string(s) representing the selected chart type(s)
* @param {Array} selectedBuildingsDataPointsSamplingRateAbbrevNestedArr An array that is made up of sub array(s) whose elements are strings representing the selected buildings, data points and sampling rates
* @returns {Boolean} true, if there are no errors thrown
*/
const checkIfSelectedBuildingDataPointsOptionsAreValid = function (
selectedChartTypeArr,
selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
) {
for (const selectedChartType of selectedChartTypeArr) {
// A heatmap can only visualize one data point
if (selectedChartType === "Heatmap") {
if (selectedBuildingsDataPointsSamplingRateAbbrevNestedArr.length === 1)
return true;
else if (
selectedBuildingsDataPointsSamplingRateAbbrevNestedArr.length > 1
) {
throw new Error("A heatmap can only display one data point at a time");
}
}
// A scatter plot requires at least two data points
if (selectedChartType === "Scatter Plot") {
if (selectedBuildingsDataPointsSamplingRateAbbrevNestedArr.length >= 2)
return true;
else if (
selectedBuildingsDataPointsSamplingRateAbbrevNestedArr.length < 2
) {
throw new Error("A scatter plot requires at least two data points");
}
}
}
};
/**
* Check if the selected aggregation type options are valid for
* drawing either a heatmp or scatter plot. If these options are
* invalid, throw an error
*
* @param {Array} selectedChartTypeArr An array of string(s) representing the selected chart type(s)
* @param {String} selectedAggregationType The selected aggregation type
* @param {String} selectedAggregationDuration The selected aggregation duration
* @returns {Boolean} true, if there are no errors thrown
*/
const checkIfSelectedAggregationOptionsAreValid = function (
selectedChartTypeArr,
selectedAggregationType,
selectedAggregationDuration
) {
for (const selectedChartType of selectedChartTypeArr) {
if (
selectedChartType === "Heatmap" ||
selectedChartType === "Scatter Plot"
) {
// For both chart types, we are interested in raw observations
if (
checkIfChartRequiresRawObservations(
selectedAggregationType,
selectedAggregationDuration
)
)
return true;
// Throw error if we attempt to use aggregated observations
else {
throw new Error(
"The selected chart type does not support aggregated results"
);
}
}
}
};
/** /**
* 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
...@@ -380,9 +460,14 @@ const getBuildingSensorSamplingRateAbbreviation = function ( ...@@ -380,9 +460,14 @@ const getBuildingSensorSamplingRateAbbreviation = function (
const getAbbreviationsForSelectedOptionsFromAllDropDownLists = function ( const getAbbreviationsForSelectedOptionsFromAllDropDownLists = function (
allSelectedOptionsArr allSelectedOptionsArr
) { ) {
// Note: The sampling rate array is the third array, therefore we skip one element // Note: The buildings + data points array is the second element and
const [selectedBuildingDataPointOptionsSplitArr, , selectedSamplingRateArr] = // the sampling rate array is the fourth element, therefore we skip the first and third elementa
allSelectedOptionsArr; const [
,
selectedBuildingDataPointOptionsSplitArr,
,
selectedSamplingRateArr,
] = allSelectedOptionsArr;
// The building is the first element // The building is the first element
const selectedBuildingsArr = selectedBuildingDataPointOptionsSplitArr.map( const selectedBuildingsArr = selectedBuildingDataPointOptionsSplitArr.map(
...@@ -417,6 +502,7 @@ export { ...@@ -417,6 +502,7 @@ export {
deleteTemperatureDifferenceOptions, deleteTemperatureDifferenceOptions,
extractTemperatureDifferenceOptions, extractTemperatureDifferenceOptions,
extractBuildingPlusSamplingRate, extractBuildingPlusSamplingRate,
checkIfChartRequiresRawObservations, checkIfSelectedBuildingDataPointsOptionsAreValid,
checkIfSelectedAggregationOptionsAreValid,
getAbbreviationsForSelectedOptionsFromAllDropDownLists, getAbbreviationsForSelectedOptionsFromAllDropDownLists,
}; };
...@@ -29,75 +29,58 @@ import { extractPropertiesFromFormattedDatastreamMetadata } from "./fetchedDataP ...@@ -29,75 +29,58 @@ import { extractPropertiesFromFormattedDatastreamMetadata } from "./fetchedDataP
/** /**
* Draw a heatmap based on the selected options from a drop-down list * Draw a heatmap based on the selected options from a drop-down list
* *
* @param {Array} selectedBuildingsDataPointsSamplingRateAbbrevArr An array which contains one or more nested arrays of abbreviations of building(s), data point(s) and sampling rate(s)
* @param {Array} observationsComboNestedArr An array that contains non-computed (raw) observations and computed (temperature difference, dT) observations * @param {Array} observationsComboNestedArr An array that contains non-computed (raw) observations and computed (temperature difference, dT) observations
* @param {Object} extractedFormattedDatastreamProperties An object that contains array(s) of formatted Datastream properties * @param {Object} extractedFormattedDatastreamProperties An object that contains array(s) of formatted Datastream properties
* @returns {undefined} undefined * @returns {undefined} undefined
*/ */
const drawHeatmapBasedOnSelectedOptions = function ( const drawHeatmapBasedOnSelectedOptions = function (
selectedBuildingsDataPointsSamplingRateAbbrevArr,
observationsComboNestedArr, observationsComboNestedArr,
extractedFormattedDatastreamProperties extractedFormattedDatastreamProperties
) { ) {
if (selectedBuildingsDataPointsSamplingRateAbbrevArr.length === 1) { // Create formatted array(s) for observations
// Create formatted array(s) for observations const formattedObservationsHeatMapNestedArr = observationsComboNestedArr.map(
const formattedObservationsHeatMapNestedArr = (observationsArr) =>
observationsComboNestedArr.map((observationsArr) => formatSensorThingsApiResponseForHeatMap(observationsArr)
formatSensorThingsApiResponseForHeatMap(observationsArr) );
);
// Note: The resulting array is nested and is not suitable for heatmap,
// Note: The resulting array is nested and is not suitable for heatmap, // extract the nested array
// extract the nested array const [formattedObservationsHeatMapArr] =
const [formattedObservationsHeatMapArr] = formattedObservationsHeatMapNestedArr;
formattedObservationsHeatMapNestedArr;
drawHeatMapHighcharts(
drawHeatMapHighcharts( formattedObservationsHeatMapArr,
formattedObservationsHeatMapArr, extractedFormattedDatastreamProperties
extractedFormattedDatastreamProperties );
);
} else if (selectedBuildingsDataPointsSamplingRateAbbrevArr.length < 1) {
throw new Error("Please select at least one data point");
} else {
throw new Error(
"This type of chart (Heatmap) can only display one data point at a time"
);
}
}; };
/** /**
* Draw a scatter plot based on the selected options from a drop-down list * Draw a scatter plot based on the selected options from a drop-down list
* *
* @param {Array} selectedBuildingsDataPointsSamplingRateAbbrevArr An array which contains one or more nested arrays of abbreviations of building(s), data point(s) and sampling rate(s)
* @param {Array} observationsComboNestedArr An array that contains non-computed (raw) observations and computed (temperature difference, dT) observations * @param {Array} observationsComboNestedArr An array that contains non-computed (raw) observations and computed (temperature difference, dT) observations
* @param {Object} extractedFormattedDatastreamProperties An object that contains array(s) of formatted Datastream properties * @param {Object} extractedFormattedDatastreamProperties An object that contains array(s) of formatted Datastream properties
* @returns {undefined} undefined * @returns {undefined} undefined
*/ */
const drawScatterPlotFromChartSelection = function ( const drawScatterPlotFromChartSelection = function (
selectedBuildingsDataPointsSamplingRateAbbrevArr,
observationsComboNestedArr, observationsComboNestedArr,
extractedFormattedDatastreamProperties extractedFormattedDatastreamProperties
) { ) {
// Check the length of buildings + data points + sampling rate array // Extract values for x-axis and y-axis
if (selectedBuildingsDataPointsSamplingRateAbbrevArr.length >= 2) { // x-axis values are first element of nested observations array
// Extract values for x-axis and y-axis const [obsXAxisArr] = observationsComboNestedArr.slice(0, 1);
// x-axis values are first element of nested observations array // y-axis values are rest of elements of nested observations array
const [obsXAxisArr] = observationsComboNestedArr.slice(0, 1); const obsYAxisNestedArr = observationsComboNestedArr.slice(1);
// y-axis values are rest of elements of nested observations array
const obsYAxisNestedArr = observationsComboNestedArr.slice(1); // Create formatted array(s) for observations
const formattedObservationsScatterPlotArr = obsYAxisNestedArr.map(
// Create formatted array(s) for observations (obsYAxisArr) =>
const formattedObservationsScatterPlotArr = obsYAxisNestedArr.map( formatSensorThingsApiResponseForScatterPlot(obsXAxisArr, obsYAxisArr)
(obsYAxisArr) => );
formatSensorThingsApiResponseForScatterPlot(obsXAxisArr, obsYAxisArr)
); drawScatterPlotHighcharts(
formattedObservationsScatterPlotArr,
drawScatterPlotHighcharts( extractedFormattedDatastreamProperties
formattedObservationsScatterPlotArr, );
extractedFormattedDatastreamProperties
);
} else {
throw new Error("A scatter plot chart requires at least two data points");
}
}; };
/** /**
......
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