"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 };