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