"use strict";
/**
* Format the response from SensorThings API to make it suitable for use in a heatmap
* @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 heatmap
*/
const formatSensorThingsApiResponseForHeatMap = function (obsArray) {
if (!obsArray) return;
const dataSTAFormatted = obsArray.map((obs) => {
// Get the date/time string; first element in input array; remove trailing "Z"
const obsDateTimeInput = obs[0].slice(0, -1);
// Get the "date" part of an observation
const obsDateInput = obs[0].slice(0, 10);
// Create Date objects
const obsDateTime = new Date(obsDateTimeInput);
const obsDate = new Date(obsDateInput);
// x-axis -> timestamp; will be the same for observations from the same date
const timestamp = Date.parse(obsDate);
// y-axis -> hourOfDay
const hourOfDay = obsDateTime.getHours();
// value -> the observation's value; second element in input array
const value = obs[1];
return [timestamp, hourOfDay, value];
});
return dataSTAFormatted;
};
/**
* Calculate the minimum and maximum values for a heatmap's color axis
* @param {Array} formattedObsArrHeatmap Response from SensorThings API formatted for use in a heatmap
* @returns {Object} An object containing the minimum and maximum values
*/
const calculateMinMaxValuesForHeatmapColorAxis = function (
formattedObsArrHeatmap
) {
// The observation value is the third element in array
const obsValueArr = formattedObsArrHeatmap.map((obs) => obs[2]);
// Extract integer part
const minValue = Math.trunc(Math.min(...obsValueArr));
const maxValue = Math.trunc(Math.max(...obsValueArr));
// Calculate the closest multiple of 5
const minObsValue = minValue - (minValue % 5);
const maxObsValue = maxValue + (5 - (maxValue % 5));
return { minObsValue, maxObsValue };
};
/**
* Draw a heatmap using Highcharts library
* @param {Array} formattedObsArrayForHeatmap Response from SensorThings API formatted for use in a heatmap
* @param {Object} formattedDatastreamMetadata Object containing Datastream metadata
* @returns {undefined} undefined
*/
const drawHeatMapHighcharts = function (
formattedObsArrayForHeatmap,
formattedDatastreamMetadata
) {
const {
datastreamDescription: DATASTREAM_DESCRIPTION,
datastreamName: DATASTREAM_NAME,
phenomenonName: PHENOMENON_NAME,
unitOfMeasurementSymbol: PHENOMENON_SYMBOL,
} = formattedDatastreamMetadata;
const {
minObsValue: MINIMUM_VALUE_COLOR_AXIS,
maxObsValue: MAXIMUM_VALUE_COLOR_AXIS,
} = calculateMinMaxValuesForHeatmapColorAxis(formattedObsArrayForHeatmap);
Highcharts.chart("chart-heatmap", {
chart: {
type: "heatmap",
zoomType: "x",
},
boost: {
useGPUTranslations: true,
},
title: {
text: DATASTREAM_DESCRIPTION,
align: "left",
x: 40,
},
subtitle: {
text: DATASTREAM_NAME,
align: "left",
x: 40,
},
xAxis: {
type: "datetime",
// min: Date.UTC(2017, 0, 1),
// max: Date.UTC(2017, 11, 31, 23, 59, 59),
labels: {
align: "left",
x: 5,
y: 14,
format: "{value:%B}", // long month
},
showLastLabel: false,
tickLength: 16,
},
yAxis: {
title: {
text: null,
},
labels: {
format: "{value}:00",
},
minPadding: 0,
maxPadding: 0,
startOnTick: false,
endOnTick: false,
tickPositions: [0, 3, 6, 9, 12, 15, 18, 21, 24],
tickWidth: 1,
min: 0,
max: 23,
reversed: true,
},
colorAxis: {
stops: [
[0, "#3060cf"],
[0.5, "#fffbbc"],
[0.9, "#c4463a"],
[1, "#c4463a"],
],
min: MINIMUM_VALUE_COLOR_AXIS,
max: MAXIMUM_VALUE_COLOR_AXIS,
startOnTick: false,
endOnTick: false,
labels: {
// format: "{value}℃",
format: `{value}${PHENOMENON_SYMBOL}`,
},
},
series: [
{
data: formattedObsArrayForHeatmap,
boostThreshold: 100,
borderWidth: 0,
nullColor: "#525252",
colsize: 24 * 36e5, // one day
tooltip: {
headerFormat: `${PHENOMENON_NAME}
`,
valueDecimals: 2,
pointFormat:
// "{point.x:%e %b, %Y} {point.y}:00: {point.value} ℃",
`{point.x:%e %b, %Y} {point.y}:00: {point.value} ${PHENOMENON_SYMBOL}`,
nullFormat: `{point.x:%e %b, %Y} {point.y}:00: null`,
},
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
},
],
});
};
export { formatSensorThingsApiResponseForHeatMap, drawHeatMapHighcharts };