Commit f000787d authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

Use raw and aggregated data when drawing charts

parent dc2e7ae0
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
} from "./src_modules/baseUrlPlusQueryParams.mjs"; } from "./src_modules/baseUrlPlusQueryParams.mjs";
import { import {
formatSensorThingsApiResponseForLineChart, formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts, drawLineChartHighcharts,
} from "./src_modules/chartLine.mjs"; } from "./src_modules/chartLine.mjs";
...@@ -30,7 +30,7 @@ import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./sr ...@@ -30,7 +30,7 @@ import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./sr
import { import {
formatDatastreamMetadataForChart, formatDatastreamMetadataForChart,
extractPropertiesFromFormattedDatastreamMetadata, extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcess.mjs"; } from "./src_modules/fetchedDataProcessing.mjs";
import { calculateVorlaufMinusRuecklaufTemperature } from "./src_modules/calculateTemperatureDiff.mjs"; import { calculateVorlaufMinusRuecklaufTemperature } from "./src_modules/calculateTemperatureDiff.mjs";
...@@ -74,7 +74,7 @@ const drawHeatmapHCUsingTempDifference = async function () { ...@@ -74,7 +74,7 @@ const drawHeatmapHCUsingTempDifference = async function () {
// Format the metadata // Format the metadata
const formattedTempDiff225MetadataNestedArr = const formattedTempDiff225MetadataNestedArr =
metadataTemperatureDiff225NestedArr.map((metadataObj) => metadataTemperatureDiff225NestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj, false) formatDatastreamMetadataForChart(metadataObj)
); );
// Extract the formatted metadata properties // Extract the formatted metadata properties
...@@ -173,12 +173,12 @@ const testLineChartMultipleSeries = async function () { ...@@ -173,12 +173,12 @@ const testLineChartMultipleSeries = async function () {
// Format the observations // Format the observations
const formattedObservationsNestedArr = observationsNestedArr.map( const formattedObservationsNestedArr = observationsNestedArr.map(
(observationsArr) => (observationsArr) =>
formatSensorThingsApiResponseForLineChart(observationsArr) formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
); );
// Format the metadata // Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataArr) => const formattedMetadataNestedArr = metadataNestedArr.map((metadataArr) =>
formatDatastreamMetadataForChart(metadataArr, false) formatDatastreamMetadataForChart(metadataArr)
); );
// Extract the formatted metadata properties // Extract the formatted metadata properties
...@@ -264,7 +264,7 @@ const drawColumnChartMonthlySumTest = async function () { ...@@ -264,7 +264,7 @@ const drawColumnChartMonthlySumTest = async function () {
// Format the metadata // Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) => const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj, true) formatDatastreamMetadataForChart(metadataObj)
); );
// Extract the formatted metadata properties // Extract the formatted metadata properties
...@@ -346,7 +346,7 @@ const drawColumnChartDailySumTest = async function () { ...@@ -346,7 +346,7 @@ const drawColumnChartDailySumTest = async function () {
// Format the metadata // Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) => const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj, true) formatDatastreamMetadataForChart(metadataObj)
); );
// Extract the formatted metadata properties // Extract the formatted metadata properties
...@@ -367,6 +367,54 @@ const drawColumnChartDailySumTest = async function () { ...@@ -367,6 +367,54 @@ const drawColumnChartDailySumTest = async function () {
} }
}; };
/**
* Test drawing of column chart using raw observations
*/
const drawColumnChartNonAggregationTest = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [observationsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// Format the observations
const formattedObservationsNestedArr = observationsNestedArr.map(
(observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
);
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataArr) =>
formatDatastreamMetadataForChart(metadataArr)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
false
);
drawColumnChartHighcharts(
formattedObservationsNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
};
/** /**
* Test drawing of line chart using aggregation / average result - monthly * Test drawing of line chart using aggregation / average result - monthly
*/ */
...@@ -433,17 +481,17 @@ const drawLineChartMonthlyAverageTest = async function () { ...@@ -433,17 +481,17 @@ const drawLineChartMonthlyAverageTest = async function () {
); );
// Format the metadata // Format the metadata
// NOTE: we use the `false` flag here because line charts are meant to work with non-aggregated data
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) => const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj, false) formatDatastreamMetadataForChart(metadataObj)
); );
// Extract the formatted metadata properties // Extract the formatted metadata properties
// NOTE: we use the `false` flag here because line charts are meant to work with non-aggregated data
const extractedFormattedDatastreamProperties = const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata( extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr, formattedMetadataNestedArr,
false true,
"monthly",
"average"
); );
drawLineChartHighcharts( drawLineChartHighcharts(
...@@ -515,17 +563,17 @@ const drawLineChartDailyAverageTest = async function () { ...@@ -515,17 +563,17 @@ const drawLineChartDailyAverageTest = async function () {
); );
// Format the metadata // Format the metadata
// NOTE: we use the `false` flag here because line charts are meant to work with non-aggregated data
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) => const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj, false) formatDatastreamMetadataForChart(metadataObj)
); );
// Extract the formatted metadata properties // Extract the formatted metadata properties
// NOTE: we use the `false` flag here because line charts are meant to work with non-aggregated data
const extractedFormattedDatastreamProperties = const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata( extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr, formattedMetadataNestedArr,
false true,
"daily",
"average"
); );
drawLineChartHighcharts( drawLineChartHighcharts(
...@@ -542,5 +590,6 @@ const drawLineChartDailyAverageTest = async function () { ...@@ -542,5 +590,6 @@ const drawLineChartDailyAverageTest = async function () {
// testLineChartMultipleSeries(); // testLineChartMultipleSeries();
// drawColumnChartMonthlySumTest(); // drawColumnChartMonthlySumTest();
// drawColumnChartDailySumTest(); // drawColumnChartDailySumTest();
// drawColumnChartNonAggregationTest();
// drawLineChartMonthlyAverageTest(); // drawLineChartMonthlyAverageTest();
// drawLineChartDailyAverageTest(); // drawLineChartDailyAverageTest();
...@@ -10,10 +10,10 @@ import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./sr ...@@ -10,10 +10,10 @@ import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./sr
import { import {
formatDatastreamMetadataForChart, formatDatastreamMetadataForChart,
extractPropertiesFromFormattedDatastreamMetadata, extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcess.mjs"; } from "./src_modules/fetchedDataProcessing.mjs";
import { import {
formatSensorThingsApiResponseForLineChart, formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts, drawLineChartHighcharts,
} from "./src_modules/chartLine.mjs"; } from "./src_modules/chartLine.mjs";
...@@ -282,7 +282,7 @@ const selectChartTypeFromDropDown = async function () { ...@@ -282,7 +282,7 @@ const selectChartTypeFromDropDown = async function () {
// Create formatted array(s) for observations - line chart // Create formatted array(s) for observations - line chart
const formattedObsLineChartNestedArr = observationsNestedArr.map( const formattedObsLineChartNestedArr = observationsNestedArr.map(
(observationsArr) => (observationsArr) =>
formatSensorThingsApiResponseForLineChart(observationsArr) formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
); );
// Create formatted array(s) for observations - heatmap // Create formatted array(s) for observations - heatmap
...@@ -293,7 +293,7 @@ const selectChartTypeFromDropDown = async function () { ...@@ -293,7 +293,7 @@ const selectChartTypeFromDropDown = async function () {
// Create formatted array(s) for metadata - same for both chart types // Create formatted array(s) for metadata - same for both chart types
const formattedMetadataArr = metadataNestedArr.map((metadataObj) => const formattedMetadataArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj, false) formatDatastreamMetadataForChart(metadataObj)
); );
// Extract the formatted metadata properties // Extract the formatted metadata properties
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./fetchData.mjs"; import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./fetchData.mjs";
import { extractPhenomenonNameFromDatastreamName } from "./fetchedDataProcess.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)
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
import { import {
chartExportOptions, chartExportOptions,
createCombinedTextDelimitedByComma, createCombinedTextDelimitedByComma,
createFullTitleForLineOrColumnChart,
createTooltipDateString,
extractSamplingRateFromDatastreamName, extractSamplingRateFromDatastreamName,
} from "./chartHelpers.mjs"; } from "./chartHelpers.mjs";
import { extractPhenomenonNameFromDatastreamName } from "./fetchedDataProcess.mjs";
/** /**
* Format a computed aggregation result to make it suitable for a column chart * Format a computed aggregation result to make it suitable for a column chart
* @param {Array} calendarDatesMonthsStrArr An array of unique calendar dates strings (in "YYYY-MM-DD" fromat) or unique calendar months strings (in "YYYY-MM" format) * @param {Array} calendarDatesMonthsStrArr An array of unique calendar dates strings (in "YYYY-MM-DD" fromat) or unique calendar months strings (in "YYYY-MM" format)
...@@ -65,64 +65,6 @@ const createSeriesOptionsForColumnChart = function ( ...@@ -65,64 +65,6 @@ const createSeriesOptionsForColumnChart = function (
); );
}; };
/**
* Creates a date string that is used as a header for a shared tooltip string for a column chart
* @param {Number} pointXAxisValue The x-axis value (Unix timestamp) which is common for a set of data points
* @param {String} aggregationInterval The aggregation interval as a string, either "daily" or "monthly"
* @returns {String} A calendar date or calendar month string that is common for a set of data points
*/
const createHeaderDateString = function (pointXAxisValue, aggregationInterval) {
if (aggregationInterval === "daily")
return `${Highcharts.dateFormat("%A, %b %e, %Y", pointXAxisValue)}`;
else if (aggregationInterval === "monthly")
return `${Highcharts.dateFormat("%b %Y", pointXAxisValue)}`;
};
/**
* Create a partial string for a column's chart title
* @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"
* @returns {String} Partial string for chart title
*/
const createPartialTitleForColumnChart = function (
aggregationInterval,
aggregationType
) {
// Case 1: No aggregation; return empty string
if (!aggregationInterval && !aggregationType) return ``;
// Case 2: Aggregation; capitalize the first characters
return `${
aggregationInterval.slice(0, 1).toUpperCase() + aggregationInterval.slice(1)
} ${aggregationType.slice(0, 1).toUpperCase() + aggregationType.slice(1)}`;
};
/**
* Create a full string for a column's chart title
* @param {Array} datastreamNamesArr An array of datastream names as strings
* @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"
* @returns {String} Full string for chart title
*/
const createFullTitleForColumnChart = function (
phenomenonNamesArr,
aggregationInterval,
aggregationType
) {
// Case 1: No aggregation; create a comma separated string of phenomenon names
if (!aggregationInterval && !aggregationType)
return `${createPartialTitleForColumnChart(
aggregationInterval,
aggregationType
)}${createCombinedTextDelimitedByComma(phenomenonNamesArr)}`;
// Case 2: Aggregation
return `${createPartialTitleForColumnChart(
aggregationInterval,
aggregationType
)} ${phenomenonNamesArr[0]}`;
};
/** /**
* Draw a column chart using Highcharts library * Draw a column chart using Highcharts library
* @param {Array} formattedAggResultArraysForColumnChart An array made up of formatted aggregated result array(s) suitable for use in a column chart * @param {Array} formattedAggResultArraysForColumnChart An array made up of formatted aggregated result array(s) suitable for use in a column chart
...@@ -133,19 +75,34 @@ const drawColumnChartHighcharts = function ( ...@@ -133,19 +75,34 @@ const drawColumnChartHighcharts = function (
formattedAggResultArraysForColumnChart, formattedAggResultArraysForColumnChart,
extractedFormattedDatastreamProperties extractedFormattedDatastreamProperties
) { ) {
// Arrays of datastream properties // Formatted datastream properties
const { let datastreamNamesArr,
datastreamNamesArr, phenomenonNamesArr,
buildingIdsPhenomenonNamesArr, buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr, unitOfMeasurementSymbolsArr,
aggregationInterval, aggregationInterval,
aggregationType, aggregationType;
} = extractedFormattedDatastreamProperties;
// Check whether the datastream properties are for aggregated observations
// Create an array of phenomenon names if (extractedFormattedDatastreamProperties?.aggregationType === undefined) {
const phenomenonNamesArr = datastreamNamesArr.map((datastreamName) => // Case 1: No aggregation
extractPhenomenonNameFromDatastreamName(datastreamName) ({
); datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
} = extractedFormattedDatastreamProperties);
} else {
// Case 2: Aggregation
({
datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
aggregationInterval,
aggregationType,
} = extractedFormattedDatastreamProperties);
}
// Create the array of series options object(s) // Create the array of series options object(s)
const seriesOptionsArr = createSeriesOptionsForColumnChart( const seriesOptionsArr = createSeriesOptionsForColumnChart(
...@@ -159,7 +116,7 @@ const drawColumnChartHighcharts = function ( ...@@ -159,7 +116,7 @@ const drawColumnChartHighcharts = function (
// Assume that we will be comparing similar phenomena, so we can use the first phenomenon symbol // Assume that we will be comparing similar phenomena, so we can use the first phenomenon symbol
const unitOfMeasurementSymbol = unitOfMeasurementSymbolsArr[0]; const unitOfMeasurementSymbol = unitOfMeasurementSymbolsArr[0];
const textChartTitle = createFullTitleForColumnChart( const textChartTitle = createFullTitleForLineOrColumnChart(
phenomenonNamesArr, phenomenonNamesArr,
aggregationInterval, aggregationInterval,
aggregationType aggregationType
...@@ -209,7 +166,7 @@ const drawColumnChartHighcharts = function ( ...@@ -209,7 +166,7 @@ const drawColumnChartHighcharts = function (
}</span>: <b>${point.y.toFixed(2)} ${ }</span>: <b>${point.y.toFixed(2)} ${
unitOfMeasurementSymbolsArr[i] unitOfMeasurementSymbolsArr[i]
}</b>`, }</b>`,
`${createHeaderDateString(this.x, aggregationInterval)}` `${createTooltipDateString(this.x, aggregationInterval)}`
); );
}, },
shared: true, shared: true,
......
...@@ -57,6 +57,68 @@ const createCombinedTextDelimitedByComma = function (metadataPropertiesArr) { ...@@ -57,6 +57,68 @@ const createCombinedTextDelimitedByComma = function (metadataPropertiesArr) {
return metadataPropertiesArr.join(", "); return metadataPropertiesArr.join(", ");
}; };
/**
* 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} aggregationType The aggregation type as a string, either "sum" or "average"
* @returns {String} Partial string for chart title
*/
const createPartialTitleForLineOrColumnChart = function (
aggregationInterval,
aggregationType
) {
// Case 1: No aggregation; return empty string
if (!aggregationInterval && !aggregationType) return ``;
// Case 2: Aggregation; capitalize the first characters
return `${
aggregationInterval.slice(0, 1).toUpperCase() + aggregationInterval.slice(1)
} ${aggregationType.slice(0, 1).toUpperCase() + aggregationType.slice(1)}`;
};
/**
* Create a full string for a line chart or column chart title
* @param {Array} datastreamNamesArr An array of datastream names as strings
* @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"
* @returns {String} Full string for chart title
*/
const createFullTitleForLineOrColumnChart = function (
phenomenonNamesArr,
aggregationInterval,
aggregationType
) {
// Case 1: No aggregation; create a comma separated string of phenomenon names
if (!aggregationInterval && !aggregationType)
return `${createPartialTitleForLineOrColumnChart(
aggregationInterval,
aggregationType
)}${createCombinedTextDelimitedByComma(phenomenonNamesArr)}`;
// Case 2: Aggregation
return `${createPartialTitleForLineOrColumnChart(
aggregationInterval,
aggregationType
)} ${phenomenonNamesArr[0]}`;
};
/**
* 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 {String} aggregationInterval The aggregation interval as a string, either "daily" or "monthly"
* @returns {String} A calendar date or calendar month string that is common for a set of data points
*/
const createTooltipDateString = function (
pointXAxisValue,
aggregationInterval
) {
if (aggregationInterval === undefined || aggregationInterval === "daily")
// When `aggregationInterval === undefined`, assume that we are displaying raw observations
return `${Highcharts.dateFormat("%A, %b %e, %Y", pointXAxisValue)}`;
else if (aggregationInterval === "monthly")
return `${Highcharts.dateFormat("%b %Y", pointXAxisValue)}`;
};
/** /**
* Extracts the sampling rate substring from a datastream name string * Extracts the sampling rate substring from a datastream name string
* @param {Array} datastreamNamesArr An array of datastream name(s) * @param {Array} datastreamNamesArr An array of datastream name(s)
...@@ -69,10 +131,22 @@ const extractSamplingRateFromDatastreamName = function (datastreamNamesArr) { ...@@ -69,10 +131,22 @@ const extractSamplingRateFromDatastreamName = function (datastreamNamesArr) {
); );
}; };
/**
* Remove the transparency (alpha channel) from a color
* @param {String} rgbaColor A color expressed in RGBA format
* @returns {String} A color in RGB format
*/
const removeTransparencyFromColor = function (rgbaColor) {
return `rgb(${rgbaColor.slice(5, -5)})`;
};
export { export {
chartExportOptions, chartExportOptions,
createCombinedTextDelimitedByAmpersand, createCombinedTextDelimitedByAmpersand,
createCombinedTextDelimitedByComma, createCombinedTextDelimitedByComma,
createFullTitleForLineOrColumnChart,
createTooltipDateString,
convertHexColorToRGBColor, convertHexColorToRGBColor,
extractSamplingRateFromDatastreamName, extractSamplingRateFromDatastreamName,
removeTransparencyFromColor,
}; };
...@@ -2,15 +2,17 @@ ...@@ -2,15 +2,17 @@
import { import {
chartExportOptions, chartExportOptions,
createFullTitleForLineOrColumnChart,
createTooltipDateString,
extractSamplingRateFromDatastreamName, extractSamplingRateFromDatastreamName,
} from "./chartHelpers.mjs"; } from "./chartHelpers.mjs";
/** /**
* Format the response from SensorThings API to make it suitable for use in a line chart * Format the response from SensorThings API to make it suitable for use in a line chart or column chart
* @param {Array} obsArray Array of observations (timestamp + value) that is response from SensorThings API * @param {Array} obsArray Array of observations (timestamp + value) that is response from SensorThings API
* @returns {Array} Array of formatted observations suitable for use in a line chart * @returns {Array} Array of formatted observations suitable for use in a line chart
*/ */
const formatSensorThingsApiResponseForLineChart = function (obsArray) { const formatSensorThingsApiResponseForLineOrColumnChart = function (obsArray) {
if (!obsArray) return; if (!obsArray) return;
return obsArray.map((result) => { return obsArray.map((result) => {
...@@ -32,12 +34,12 @@ const createCombinedTextForLineChartTitles = function (phenomenonNamesArr) { ...@@ -32,12 +34,12 @@ const createCombinedTextForLineChartTitles = function (phenomenonNamesArr) {
/** /**
* Creates an options object for each series drawn in the line chart * Creates an options object for each series drawn in the line chart
* @param {Array} formattedObsArraysForLineChart An array of formatted observation array(s) from one or more datastreams * @param {Array} formattedObsArraysForLineChart An array of formatted observation array(s) from one or more datastreams
* @param {Array} phenomenonNamesArr An array of phenomenon name(s) * @param {Array} buildingIdsPhenomenonNamesArr An array of string(s) made up of building ID(s) + phenomenon name(s)
* @returns {Array} An array made up of series options object(s) * @returns {Array} An array made up of series options object(s)
*/ */
const createSeriesOptionsForLineChart = function ( const createSeriesOptionsForLineChart = function (
formattedObsArraysForLineChart, formattedObsArraysForLineChart,
phenomenonNamesArr buildingIdsPhenomenonNamesArr
) { ) {
// An array of colors, in hexadecimal format, provided by the global Highcharts object // An array of colors, in hexadecimal format, provided by the global Highcharts object
const seriesColors = Highcharts.getOptions().colors; const seriesColors = Highcharts.getOptions().colors;
...@@ -46,16 +48,19 @@ const createSeriesOptionsForLineChart = function ( ...@@ -46,16 +48,19 @@ const createSeriesOptionsForLineChart = function (
const seriesColorsArr = [...seriesColors]; const seriesColorsArr = [...seriesColors];
// Create an array of seriesOptions objects // Create an array of seriesOptions objects
// Assumes that the observation array of arrays and phenomenon names array are of equal length // Assumes that the observation array of arrays and building IDs + phenomenon names array are of equal length
// Use one of the arrays for looping // Use one of the arrays for looping
if (formattedObsArraysForLineChart.length !== phenomenonNamesArr.length) if (
formattedObsArraysForLineChart.length !==
buildingIdsPhenomenonNamesArr.length
)
throw new Error( throw new Error(
"The observations array and phenomenon names array have different lengths" "The observations array and phenomenon names array have different lengths"
); );
return formattedObsArraysForLineChart.map((formattedObsArray, i) => { return formattedObsArraysForLineChart.map((formattedObsArray, i) => {
return { return {
name: `${phenomenonNamesArr[i]}`, name: `${buildingIdsPhenomenonNamesArr[i]}`,
data: formattedObsArray, data: formattedObsArray,
color: seriesColorsArr[i], color: seriesColorsArr[i],
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
...@@ -74,15 +79,40 @@ const drawLineChartHighcharts = function ( ...@@ -74,15 +79,40 @@ const drawLineChartHighcharts = function (
extractedFormattedDatastreamProperties extractedFormattedDatastreamProperties
) { ) {
// Arrays of datastream properties // Arrays of datastream properties
const { let datastreamNamesArr,
datastreamNamesArr,
phenomenonNamesArr, phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr, unitOfMeasurementSymbolsArr,
} = extractedFormattedDatastreamProperties; aggregationInterval,
aggregationType;
// Check whether the datastream properties are for aggregated observations
if (extractedFormattedDatastreamProperties?.aggregationType === undefined) {
// Case 1: No aggregation
({
datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
} = extractedFormattedDatastreamProperties);
} else {
// Case 2: Aggregation
({
datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
aggregationInterval,
aggregationType,
} = extractedFormattedDatastreamProperties);
}
// Chart title and subtitle text // Chart title and subtitle text
const textChartTitle = const textChartTitle = createFullTitleForLineOrColumnChart(
createCombinedTextForLineChartTitles(phenomenonNamesArr); phenomenonNamesArr,
aggregationInterval,
aggregationType
);
const textChartSubtitle = `Sampling rate(s): ${createCombinedTextForLineChartTitles( const textChartSubtitle = `Sampling rate(s): ${createCombinedTextForLineChartTitles(
extractSamplingRateFromDatastreamName(datastreamNamesArr) extractSamplingRateFromDatastreamName(datastreamNamesArr)
...@@ -91,7 +121,7 @@ const drawLineChartHighcharts = function ( ...@@ -91,7 +121,7 @@ const drawLineChartHighcharts = function (
// Create the array of series options object(s) // Create the array of series options object(s)
const seriesOptionsArr = createSeriesOptionsForLineChart( const seriesOptionsArr = createSeriesOptionsForLineChart(
formattedObsArraysForLineChart, formattedObsArraysForLineChart,
phenomenonNamesArr, buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr unitOfMeasurementSymbolsArr
); );
...@@ -119,7 +149,9 @@ const drawLineChartHighcharts = function ( ...@@ -119,7 +149,9 @@ const drawLineChartHighcharts = function (
// Our tooltip is split // Our tooltip is split
// this.x -- common for all points // this.x -- common for all points
// this.points -- an array containing properties for each series // this.points -- an array containing properties for each series
return [`${Highcharts.dateFormat("%A, %b %e, %Y", this.x)}`].concat( return [
`${createTooltipDateString(this.x, aggregationInterval)}`,
].concat(
this.points this.points
? this.points.map( ? this.points.map(
(point, i) => (point, i) =>
...@@ -140,4 +172,7 @@ const drawLineChartHighcharts = function ( ...@@ -140,4 +172,7 @@ const drawLineChartHighcharts = function (
}); });
}; };
export { formatSensorThingsApiResponseForLineChart, drawLineChartHighcharts }; export {
formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts,
};
...@@ -6,6 +6,7 @@ import { ...@@ -6,6 +6,7 @@ import {
createCombinedTextDelimitedByAmpersand, createCombinedTextDelimitedByAmpersand,
createCombinedTextDelimitedByComma, createCombinedTextDelimitedByComma,
extractSamplingRateFromDatastreamName, extractSamplingRateFromDatastreamName,
removeTransparencyFromColor,
} from "./chartHelpers.mjs"; } from "./chartHelpers.mjs";
/** /**
...@@ -457,12 +458,18 @@ const drawScatterPlotHighcharts = function ( ...@@ -457,12 +458,18 @@ const drawScatterPlotHighcharts = function (
tooltip: { tooltip: {
formatter() { formatter() {
const headerString = `${this.series.name}<br>`; // The color contained in the series object is in RGBA format,
// convert it to RGB format so that the text in the tooltip is more legible
const headerString = `<span style="color:${removeTransparencyFromColor(
this.point.color
)}">${this.series.name}</span> <br>`;
const pointString = `<b>${this.point.y.toFixed( const pointString = `<b>${this.point.y.toFixed(
2 2
)} ${UNIT_OF_MEASUREMENT_SYMBOL}, ${this.point.x.toFixed( )} ${UNIT_OF_MEASUREMENT_SYMBOL}, ${this.point.x.toFixed(
2 2
)} ${UNIT_OF_MEASUREMENT_SYMBOL}</b>`; )} ${UNIT_OF_MEASUREMENT_SYMBOL}</b>`;
return headerString + pointString; return headerString + pointString;
}, },
}, },
......
...@@ -46,21 +46,9 @@ const extractBuildingIdPhenomenonNameFromDatastreamName = function ( ...@@ -46,21 +46,9 @@ const extractBuildingIdPhenomenonNameFromDatastreamName = function (
/** /**
* Format the response containing a Datastream's metadata from Sensorthings API * Format the response containing a Datastream's metadata from Sensorthings API
* @param {Object} datastreamMetadata An object containing a Datastream's metadata * @param {Object} datastreamMetadata An object containing a Datastream's metadata
* @param {Boolean} isMetadataForAggregation A flag to determine if the datastream metadata will be used for aggregation. Set to `true` if metadata will be used for aggregation, `false` if not
* @returns {Object} An object containing the formatted metadata that is suitable for use in a chart * @returns {Object} An object containing the formatted metadata that is suitable for use in a chart
*/ */
const formatDatastreamMetadataForChart = function ( const formatDatastreamMetadataForChart = function (datastreamMetadata) {
datastreamMetadata,
isMetadataForAggregation
) {
if (
datastreamMetadata === undefined ||
isMetadataForAggregation === undefined
)
throw new Error(
"This function expects two arguments, ensure that both have been supplied"
);
const { const {
description: datastreamDescription, description: datastreamDescription,
name: datastreamName, name: datastreamName,
...@@ -80,19 +68,10 @@ const formatDatastreamMetadataForChart = function ( ...@@ -80,19 +68,10 @@ const formatDatastreamMetadataForChart = function (
unitOfMeasurement.symbol unitOfMeasurement.symbol
); );
// Case 1: Metadata NOT USED for aggregation; "isMetadataForAggregation" = false
if (!isMetadataForAggregation)
return {
datastreamDescription,
datastreamName,
phenomenonName,
unitOfMeasurementSymbol,
};
// Case 2: Metadata USED for aggregation; "isMetadataForAggregation" = true
return { return {
datastreamDescription, datastreamDescription,
datastreamName, datastreamName,
phenomenonName,
buildingIdPhenomenonName, buildingIdPhenomenonName,
unitOfMeasurementSymbol, unitOfMeasurementSymbol,
}; };
...@@ -174,6 +153,7 @@ const extractPropertiesFromFormattedDatastreamMetadata = function ( ...@@ -174,6 +153,7 @@ const extractPropertiesFromFormattedDatastreamMetadata = function (
datastreamDescriptionsArr, datastreamDescriptionsArr,
datastreamNamesArr, datastreamNamesArr,
phenomenonNamesArr, phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr, unitOfMeasurementSymbolsArr,
}; };
...@@ -181,6 +161,7 @@ const extractPropertiesFromFormattedDatastreamMetadata = function ( ...@@ -181,6 +161,7 @@ const extractPropertiesFromFormattedDatastreamMetadata = function (
return { return {
datastreamDescriptionsArr, datastreamDescriptionsArr,
datastreamNamesArr, datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr, buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr, unitOfMeasurementSymbolsArr,
aggregationInterval, aggregationInterval,
......
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