"use strict";
import {
chartExportOptions,
createFullTitleForLineOrColumnChart,
createSubtitleForChart,
createTooltipDateString,
} from "./chartHelpers.mjs";
/**
* 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
* @returns {Array} Array of formatted observations suitable for use in a line chart
*/
const formatSensorThingsApiResponseForLineOrColumnChart = function (obsArray) {
if (!obsArray) return;
return obsArray.map((result) => {
const timestampObs = new Date(result[0].slice(0, -1)).getTime(); // slice() removes trailing "Z" character in timestamp
const valueObs = result[1];
return [timestampObs, valueObs];
});
};
/**
* 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} 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)
*/
const createSeriesOptionsForLineChart = function (
formattedObsArraysForLineChart,
buildingIdsPhenomenonNamesArr
) {
// An array of colors, in hexadecimal format, provided by the global Highcharts object
const seriesColors = Highcharts.getOptions().colors;
// Create a copy of the colors array
const seriesColorsArr = [...seriesColors];
// Create an array of seriesOptions objects
// Assumes that the observation array of arrays and building IDs + phenomenon names array are of equal length
// Use one of the arrays for looping
if (
formattedObsArraysForLineChart.length !==
buildingIdsPhenomenonNamesArr.length
) {
throw new Error(
"The observations array and phenomenon names array have different lengths"
);
} else {
return formattedObsArraysForLineChart.map((formattedObsArray, i) => {
return {
name: `${buildingIdsPhenomenonNamesArr[i]}`,
data: formattedObsArray,
color: seriesColorsArr[i],
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
};
});
}
};
/**
* Draw a line chart using Highcharts library
* @param {Array} formattedObsArraysForLineChart An array made up of formatted observation array(s) suitable for use in a line chart. The observations may either be raw or aggregated
* @param {Object} extractedFormattedDatastreamPropertiesArr An object that contains arrays of formatted Datastream properties
* @returns {undefined} undefined
*/
const drawLineChartHighcharts = function (
formattedObsArraysForLineChart,
extractedFormattedDatastreamProperties
) {
// Arrays of datastream properties
let datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
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
const textChartTitle = createFullTitleForLineOrColumnChart(
phenomenonNamesArr,
aggregationInterval,
aggregationType
);
const textChartSubtitle = createSubtitleForChart(datastreamNamesArr);
// Create the array of series options object(s)
const seriesOptionsArr = createSeriesOptionsForLineChart(
formattedObsArraysForLineChart,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr
);
Highcharts.stockChart("chart-line", {
chart: {
zoomType: "x",
},
rangeSelector: {
selected: 5,
},
title: {
text: textChartTitle,
"align": "center",
},
subtitle: {
text: textChartSubtitle,
align: "center",
},
tooltip: {
formatter() {
// Our tooltip is split
// this.x -- common for all points
// this.points -- an array containing properties for each series
return [
`${createTooltipDateString(this.x, aggregationInterval)}`,
].concat(
this.points
? this.points.map(
(point, i) =>
`${
point.series.name
}: ${point.y.toFixed(2)} ${
unitOfMeasurementSymbolsArr[i]
}`
)
: []
);
},
},
exporting: chartExportOptions,
series: seriesOptionsArr,
});
};
export {
formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts,
};