An error occurred while loading the file. Please try again.
chartHeatmap.mjs 5.28 KiB
"use strict";
import { chartExportOptions } from "./chartExport.mjs";
/**
 * 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;
  return 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];
  });
/**
 * 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} extractedFormattedDatastreamProperties An object that contains arrays of formatted Datastream properties
 * @returns {undefined} undefined
const drawHeatMapHighcharts = function (
  formattedObsArrayForHeatmap,
  extractedFormattedDatastreamProperties
) {
  // Arrays of datastream properties
  const {
    datastreamDescriptionsArr,
    datastreamNamesArr,
    phenomenonNamesArr,
    unitOfMeasurementSymbolsArr,
  } = extractedFormattedDatastreamProperties;
const [DATASTREAM_DESCRIPTION] = datastreamDescriptionsArr; const [DATASTREAM_NAME] = datastreamNamesArr; const [PHENOMENON_NAME] = phenomenonNamesArr; const [PHENOMENON_SYMBOL] = unitOfMeasurementSymbolsArr; 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}${PHENOMENON_SYMBOL}`, }, }, exporting: chartExportOptions, tooltip: { formatter() { const headerString = `${PHENOMENON_NAME}<br/>`; // Check whether the point value is null or not; this will determine the string that we'll render const pointString = this.point.value === null ? `${Highcharts.dateFormat("%e %b, %Y", this.point.x)} ${ this.point.y }:00:00 <b>null</b>` : `${Highcharts.dateFormat("%e %b, %Y", this.point.x)} ${ this.point.y }:00:00 <b>${this.point.value.toFixed( 2 )} ${PHENOMENON_SYMBOL}</b>`; return headerString + pointString; }, }, series: [ { data: formattedObsArrayForHeatmap, boostThreshold: 100, borderWidth: 0, nullColor: "#525252", colsize: 24 * 36e5, // one day turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release }, ], }); }; export { formatSensorThingsApiResponseForHeatMap, drawHeatMapHighcharts };