appChart.js 10.8 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 {
25
26
  showLoadingSpinner,
  hideLoadingSpinner,
27
28
  disableDrawChartButton,
  enableDrawChartButton,
29
} from "./src_modules/loadingIndicator.mjs";
30

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

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

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

50
import { drawColumnChartBasedOnSelectedOptions } from "./src_modules/dropDownListChartColumn.mjs";
51
52
53
54
55

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

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

56
import { drawScatterPlotBasedOnSelectedOptions } from "./src_modules/dropDownListChartScatterPlot.mjs";
Pithon Kabiro's avatar
Pithon Kabiro committed
57

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

68
/**
69
70
71
72
73
74
 * 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
75
 */
76
const drawChartUsingSelectedOptions = async function () {
77
  try {
78
    // Note: The chart type amd aggregation type + duration are the first and
79
80
    // third elements respectively, we have ignored the second and fourth elements
    const [selectedChartTypeArr, , selectedAggregationTypeDurationArr] =
81
      getSelectedOptionsFromAllDropDownLists();
82

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

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

96
97
98
99
100
101
102
103
104
105
    // 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";

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    // 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
      );

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

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

    // Display the loading indicator
    showLoadingSpinner();

145
146
147
    // Disable the 'draw chart' button
    disableDrawChartButton();

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

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

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

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

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

188
189
190
191
192
    // 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)"
193
194
        ? observationsCombinedNestedArr
        : observationsCombinedNestedArr.map((observationsArr) =>
195
196
197
            extractObservationsWithinDatesInterval(
              observationsArr,
              selectedSamplingRateAbbrev,
198
199
              AGGREGATION_START_DATE,
              AGGREGATION_STOP_DATE
200
201
            )
          );
202

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

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

        // We are interested in raw observations ONLY
        case "Scatter Plot":
          if (
            selectedAggregationOptionsAreValid &&
            selectedBuildingDataPointsOptionsAreValid
          ) {
230
            drawScatterPlotBasedOnSelectedOptions(
231
              observationsComboNestedFinalArr,
232
              rawObsExtractedFormattedDatastreamProperties
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
            );
          }
          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,
251
              rawObsExtractedFormattedDatastreamProperties
252
            );
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
          }
          // Aggregated observations
          else {
            drawLineChartBasedOnSelectedAggregationOptions(
              selectedAggregationType,
              selectedAggregationDuration,
              observationsComboNestedFinalArr,
              selectedSamplingRateAbbrev,
              uniqueCalendarDatesNestedArr,
              formattedMetadataNestedArr
            );
          }
          break;

        case "Column":
268
269
270
271
272
273
274
275
          drawColumnChartBasedOnSelectedOptions(
            selectedAggregationType,
            selectedAggregationDuration,
            observationsComboNestedFinalArr,
            selectedSamplingRateAbbrev,
            uniqueCalendarDatesNestedArr,
            formattedMetadataNestedArr
          );
276
          break;
277

278
279
        default:
          throw new Error("None of the chart type options were selected");
280
      }
281
    }
282
283
  } catch (err) {
    console.error(err);
284
285
286

    // Display a dialog window with the error message
    alert(err);
287
  } finally {
288
289
290
    // Enable the 'draw chart' button
    enableDrawChartButton();

291
292
    // Hide the loading indicator
    hideLoadingSpinner();
293
294
295
  }
};

296
297
298
299
300
document.addEventListener("DOMContentLoaded", afterDocumentLoads);

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