chartLine.js 5.36 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
"use strict";

/**
 * Format the response from SensorThings API to make it suitable for use in a line 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 formatSensorThingsApiResponseForLineChart = function (obsArray) {
  if (!obsArray) return;

  const dataSTAFormatted = 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];
  });

  return dataSTAFormatted;
};

/**
 * Extract the properties that make up the formatted datastream metadata object(s)
 * @param {Array} formattedDatastreamsMetadataArr An array of formatted metadata object(s) from one or more datastreams
 * @returns {Object} An object that contains array(s) of formatted datastream metadata properties
 */
const extractPropertiesFromDatastreamMetadata = function (
  formattedDatastreamsMetadataArr
) {
  // Create arrays from the properties of the formatted datastream metadata
  const datastreamDescriptionsArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.datastreamDescription
  );

  const datastreamNamesArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.datastreamName
  );

  const phenomenonNamesArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.phenomenonName
  );

  const unitOfMeasurementSymbolsArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.unitOfMeasurementSymbol
  );

  return {
    datastreamDescriptionsArr,
    datastreamNamesArr,
    phenomenonNamesArr,
    unitOfMeasurementSymbolsArr,
  };
};

/**
 * Extracts the sampling rate substring from a datastream name string
 * @param {Array} datastreamNamesArr An array of datastream name(s)
 * @returns {Array} An array containing the sampling rate substring(s)
 */
const extractSamplingRateFromDatastreamName = function (datastreamNamesArr) {
  // The sampling rate string is the last word in the Datastream name string
  return datastreamNamesArr.map((datastreamName) =>
    datastreamName.split(" ").pop()
  );
};

/**
 * Concatenates metadata properties to create a string for either the title or subtitle of a line chart
 * @param {Array} datastreamMetadataPropArr An array of metadata property strings
 * @returns {String} A string of comma separated metadata property strings
 */
const createCombinedTextForLineChartTitles = function (
  datastreamMetadataPropArr
) {
  return datastreamMetadataPropArr.join(", ");
};

/**
 * 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} phenomenonNamesArr An array of phenomenon name(s)
 * @param {Array} phenomenonSymbolsArr An array of phenomenon symbol(s)
 * @returns {Array} An array made up of series options object(s)
 */
const createSeriesOptionsForLineChart = function (
  formattedObsArraysForLineChart,
  phenomenonNamesArr,
  phenomenonSymbolsArr
) {
  // An array of colors provided by the Highcharts object
  const seriesColors = Highcharts.getOptions().colors;

  // Create an array of seriesOptions objects
  // Assumes that the observation array of arrays, phenomenon names array and phenomenon symbols array are of equal length
  // Use one of the arrays for looping
  return formattedObsArraysForLineChart.map((formattedObsArray, i) => {
    return {
      name: `${phenomenonNamesArr[i]} (${phenomenonSymbolsArr[i]})`,
      data: formattedObsArray,
      color: seriesColors[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
 * @param {Object} formattedDatastreamMetadataArr An array made up of object(s) containing Datastream metadata
 * @returns {undefined} undefined
 */
const drawLineChartHighcharts = function (
  formattedObsArraysForLineChart,
  formattedDatastreamMetadataArr
) {
  // Arrays of datastream properties
  const {
    datastreamNamesArr,
    phenomenonNamesArr,
    unitOfMeasurementSymbolsArr,
  } = extractPropertiesFromDatastreamMetadata(formattedDatastreamMetadataArr);

  // Create the array of series options object(s)
  const seriesOptionsArr = createSeriesOptionsForLineChart(
    formattedObsArraysForLineChart,
    phenomenonNamesArr,
    unitOfMeasurementSymbolsArr
  );

  Highcharts.stockChart("chart-line", {
    chart: {
      zoomType: "x",
    },

    rangeSelector: {
      selected: 5,
    },

    title: {
      text: createCombinedTextForLineChartTitles(phenomenonNamesArr),
      "align": "left",
    },

    subtitle: {
      text: `Sampling rate(s): ${createCombinedTextForLineChartTitles(
        extractSamplingRateFromDatastreamName(datastreamNamesArr)
      )}`,
      align: "left",
    },

    tooltip: {
      pointFormat:
        '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> <br/>',
      valueDecimals: 2,
    },

    series: seriesOptionsArr,
  });
};

export { formatSensorThingsApiResponseForLineChart, drawLineChartHighcharts };