appChart.js 11.7 KB
Newer Older
Pithon Kabiro's avatar
Pithon Kabiro committed
1
"use strict";
Pithon Kabiro's avatar
Pithon Kabiro committed
2

3
4
5
6
import {
  BASE_URL,
  QUERY_PARAMS_COMBINED,
} from "./src_modules/baseUrlPlusQueryParams.mjs";
7

8
import { calculateVorlaufMinusRuecklaufTemperature } from "./src_modules/calculateTemperatureDiff.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
9

10
11
12
13
import {
  getMetadataPlusObservationsFromSingleOrMultipleDatastreams,
  isFetchingRawMetadataPlusObservationsSuccessful,
} from "./src_modules/fetchData.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
14

15
import {
16
17
18
  formatDatastreamMetadataForChart,
  extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcessing.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
19

20
21
22
import { formatSensorThingsApiResponseForLineOrColumnChart } from "./src_modules/chartHelpers.mjs";

import { drawLineChartHighcharts } from "./src_modules/chartLine.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
23

24
import { drawColumnChartHighcharts } from "./src_modules/chartColumn.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
25

26
import {
27
28
  showLoadingSpinner,
  hideLoadingSpinner,
29
30
  disableDrawChartButton,
  enableDrawChartButton,
31
} from "./src_modules/loadingIndicator.mjs";
32

33
import { styleAllDropDownLists } from "./src_modules/dropDownListStyling.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
34

35
import {
36
  extractObservationsWithinDatesInterval,
37
  extractUniqueCalendarDatesFromTimestamp,
38
39
40
} from "./src_modules/aggregateHelpers.mjs";

import {
41
42
43
44
45
46
  splitMultipleOptionsTextDelimitedBySlash,
  getSelectedOptionsFromAllDropDownLists,
  checkIfSelectedOptionsContainTemperatureDifference,
  deleteTemperatureDifferenceOptions,
  extractTemperatureDifferenceOptions,
  extractBuildingPlusSamplingRate,
47
48
  checkIfSelectedBuildingDataPointsOptionsAreValid,
  checkIfSelectedAggregationOptionsAreValid,
49
50
  getAbbreviationsForSelectedOptionsFromAllDropDownLists,
} from "./src_modules/dropDownListHelpers.mjs";
51

52
53
54
55
56
57
58
import { drawColumnChartBasedOnSelectedAggregationOptions } from "./src_modules/dropDownListChartColumn.mjs";

import { drawHeatmapBasedOnSelectedOptions } from "./src_modules/dropDownListChartHeatmap.mjs";

import { drawLineChartBasedOnSelectedAggregationOptions } from "./src_modules/dropDownListChartLine.mjs";

import { drawScatterPlotFromChartSelection } from "./src_modules/dropDownListChartScatterPlot.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
59

60
/**
61
62
63
64
 * Callback function that wraps the logic of populating the linked drop down lists.
 * Will run on `DOMContentLoaded` event
 *
 * @returns {undefined}
65
 */
66
const afterDocumentLoads = function () {
67
  styleAllDropDownLists();
68
69
};

70
/**
71
72
73
74
75
76
 * Callback function that draws a chart using options from the drop-down list that
 * have been selected by a user.
 * Will be run when the user clicks a button
 *
 * @async
 * @returns {undefined} undefined
77
 */
78
const drawChartUsingSelectedOptions = async function () {
79
  try {
80
    // Note: The chart type amd aggregation type + duration are the first and
81
82
    // third elements respectively, we have ignored the second and fourth elements
    const [selectedChartTypeArr, , selectedAggregationTypeDurationArr] =
83
      getSelectedOptionsFromAllDropDownLists();
84

85
86
87
    // Note: the resulting array is nested, it only has one sub-array
    // Separate the aggregation type and the aggregation duration strings
    const [[selectedAggregationType, selectedAggregationDuration]] =
88
89
      splitMultipleOptionsTextDelimitedBySlash(
        selectedAggregationTypeDurationArr
90
91
      );

92
    // Array of building(s) + data point(s) + sampling rate
93
    const selectedBuildingsDataPointsSamplingRateAbbrevNestedArr =
94
      getAbbreviationsForSelectedOptionsFromAllDropDownLists(
95
        getSelectedOptionsFromAllDropDownLists()
96
97
      );

98
99
100
101
102
103
104
105
106
107
    // The formatted abbreviations array is nested, we are interested in the first sub-array
    // We assume that all the phenomena have the same sampling rate
    // Extract the formatted sampling rate string - used by ALL chart types
    const [[, , selectedSamplingRateAbbrev]] =
      selectedBuildingsDataPointsSamplingRateAbbrevNestedArr;

    // User-specified start date and end date for aggregation - used by MULTIPLE chart types
    const AGGREGATION_START_DATE = "2020-01-01";
    const AGGREGATION_STOP_DATE = "2020-12-31";

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
    // The values of these references is either equal to `true` or an error will be thrown
    // We would like the errors to be thrown at this point before we begin performing any asynchronous tasks
    const selectedAggregationOptionsAreValid =
      checkIfSelectedAggregationOptionsAreValid(
        selectedChartTypeArr,
        selectedAggregationType,
        selectedAggregationDuration
      );

    const selectedBuildingDataPointsOptionsAreValid =
      checkIfSelectedBuildingDataPointsOptionsAreValid(
        selectedChartTypeArr,
        selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
      );

123
124
    // Check whether we have dT (temperature difference), if so, delete these options,
    // then compute abbreviations for raw observations
125
    const selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr =
126
      checkIfSelectedOptionsContainTemperatureDifference(
127
        selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
128
      )
129
        ? deleteTemperatureDifferenceOptions(
130
            selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
131
          )
132
        : selectedBuildingsDataPointsSamplingRateAbbrevNestedArr;
133

134
    // Check if we have dT (temperature difference), if so, extract these options
135
    const selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr =
136
      checkIfSelectedOptionsContainTemperatureDifference(
137
        selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
138
139
      )
        ? extractTemperatureDifferenceOptions(
140
            selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
141
142
143
144
145
146
          )
        : [];

    // Display the loading indicator
    showLoadingSpinner();

147
148
149
    // Disable the 'draw chart' button
    disableDrawChartButton();

150
151
    // Fetch and extract the observations + metadata / raw observations
    const [observationsRawNestedArr, metadataRawNestedArr] =
152
      selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr.length === 0
153
154
155
156
        ? [[], []]
        : await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
            BASE_URL,
            QUERY_PARAMS_COMBINED,
157
            selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr
158
159
          );

160
161
    // Fetch and extract the observations + metadata / temperature difference (dT)
    const [observationsTempDiffNestedArr, metadataTempDiffNestedArr] =
162
      selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr.length === 0
163
164
165
166
167
        ? [[], []]
        : await calculateVorlaufMinusRuecklaufTemperature(
            BASE_URL,
            QUERY_PARAMS_COMBINED,
            extractBuildingPlusSamplingRate(
168
              selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr
169
170
171
            )
          );

172
173
    // Create and extract the combined observations and metadata
    const [observationsCombinedNestedArr, metadataCombinedNestedArr] = [
174
175
      [...observationsRawNestedArr, ...observationsTempDiffNestedArr],
      [...metadataRawNestedArr, ...metadataTempDiffNestedArr],
176
    ];
177

178
    // Create formatted array(s) for metadata - used by ALL chart types
179
    const formattedMetadataNestedArr = metadataCombinedNestedArr.map(
180
      (metadataObj) => formatDatastreamMetadataForChart(metadataObj)
181
182
    );

183
    // Extract the formatted metadata properties for the raw observations - used by ALL chart types
184
    const rawObsExtractedFormattedDatastreamProperties =
185
186
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
187
        false
188
189
      );

190
191
192
193
194
    // Create final array of observations- used by MULTIPLE chart types
    // If we are performing aggregation, it was envisioned that the user would
    // select observations that fall within a start and end date
    const observationsComboNestedFinalArr =
      selectedAggregationType === "None (raw data)"
195
196
        ? observationsCombinedNestedArr
        : observationsCombinedNestedArr.map((observationsArr) =>
197
198
199
            extractObservationsWithinDatesInterval(
              observationsArr,
              selectedSamplingRateAbbrev,
200
201
              AGGREGATION_START_DATE,
              AGGREGATION_STOP_DATE
202
203
            )
          );
204

205
    // Unique calendar dates - used by MULTIPLE chart types
206
    const uniqueCalendarDatesNestedArr = observationsComboNestedFinalArr.map(
207
208
209
210
      (observationsArr) =>
        extractUniqueCalendarDatesFromTimestamp(observationsArr)
    );

211
    for (const selectedChartType of selectedChartTypeArr) {
212
213
214
215
216
217
218
219
220
      switch (selectedChartType) {
        // We are interested in raw observations ONLY
        case "Heatmap":
          if (
            selectedAggregationOptionsAreValid &&
            selectedBuildingDataPointsOptionsAreValid
          ) {
            drawHeatmapBasedOnSelectedOptions(
              observationsComboNestedFinalArr,
221
              rawObsExtractedFormattedDatastreamProperties
222
            );
223
224
225
226
227
228
229
230
231
232
233
          }
          break;

        // We are interested in raw observations ONLY
        case "Scatter Plot":
          if (
            selectedAggregationOptionsAreValid &&
            selectedBuildingDataPointsOptionsAreValid
          ) {
            drawScatterPlotFromChartSelection(
              observationsComboNestedFinalArr,
234
              rawObsExtractedFormattedDatastreamProperties
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
            );
          }
          break;

        // We are interested in BOTH raw observations and aggregated observations
        case "Line":
          // Raw observations
          if (selectedAggregationType === "None (raw data)") {
            // Create formatted array(s) for observations
            const formattedRawObservationsLineChartNestedArr =
              observationsComboNestedFinalArr.map((observationsArr) =>
                formatSensorThingsApiResponseForLineOrColumnChart(
                  observationsArr
                )
              );

            drawLineChartHighcharts(
              formattedRawObservationsLineChartNestedArr,
253
              rawObsExtractedFormattedDatastreamProperties
254
            );
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
          }
          // Aggregated observations
          else {
            drawLineChartBasedOnSelectedAggregationOptions(
              selectedAggregationType,
              selectedAggregationDuration,
              observationsComboNestedFinalArr,
              selectedSamplingRateAbbrev,
              uniqueCalendarDatesNestedArr,
              formattedMetadataNestedArr
            );
          }
          break;

        // We are interested in BOTH raw observations and aggregated observations
        case "Column":
          // Raw observations
          if (selectedAggregationType === "None (raw data)") {
            // Create formatted array(s) for observations
            const formattedRawObservationsColumnChartNestedArr =
              observationsComboNestedFinalArr.map((observationsArr) =>
                formatSensorThingsApiResponseForLineOrColumnChart(
                  observationsArr
                )
              );

            drawColumnChartHighcharts(
              formattedRawObservationsColumnChartNestedArr,
283
              rawObsExtractedFormattedDatastreamProperties
284
285
286
287
288
289
290
291
292
293
294
295
296
297
            );
          }
          // Aggregated observations
          else {
            drawColumnChartBasedOnSelectedAggregationOptions(
              selectedAggregationType,
              selectedAggregationDuration,
              observationsComboNestedFinalArr,
              selectedSamplingRateAbbrev,
              uniqueCalendarDatesNestedArr,
              formattedMetadataNestedArr
            );
          }
          break;
298

299
300
        default:
          throw new Error("None of the chart type options were selected");
301
      }
302
    }
303
304
  } catch (err) {
    console.error(err);
305
306
307

    // Display a dialog window with the error message
    alert(err);
308
  } finally {
309
310
311
    // Enable the 'draw chart' button
    enableDrawChartButton();

312
313
    // Hide the loading indicator
    hideLoadingSpinner();
314
315
316
  }
};

317
318
319
320
321
document.addEventListener("DOMContentLoaded", afterDocumentLoads);

document
  .querySelector("#btn-draw-chart")
  .addEventListener("click", drawChartUsingSelectedOptions);