@aguacerowx/javascript-sdk 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AguaceroCore.js +62 -35
- package/dist/dictionaries.js +1 -1
- package/dist/events.js +11 -1
- package/dist/index.js +14 -1
- package/package.json +6 -6
- package/src/AguaceroCore.js +37 -32
- package/src/dictionaries.js +1 -1
- package/src/events.js +13 -1
- package/src/index.js +3 -1
package/dist/AguaceroCore.js
CHANGED
|
@@ -117,17 +117,20 @@ class AguaceroCore extends _events.EventEmitter {
|
|
|
117
117
|
const timestamps = this.mrmsStatus[this.state.variable] || [];
|
|
118
118
|
availableTimestamps = [...timestamps].reverse();
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
const eventPayload = {
|
|
121
121
|
...this.state,
|
|
122
122
|
availableModels: this.modelStatus ? Object.keys(this.modelStatus).sort() : [],
|
|
123
123
|
availableRuns: ((_this$modelStatus = this.modelStatus) === null || _this$modelStatus === void 0 ? void 0 : _this$modelStatus[this.state.model]) || {},
|
|
124
124
|
availableHours: this.state.isMRMS ? [] : ((_this$modelStatus2 = this.modelStatus) === null || _this$modelStatus2 === void 0 || (_this$modelStatus2 = _this$modelStatus2[this.state.model]) === null || _this$modelStatus2 === void 0 || (_this$modelStatus2 = _this$modelStatus2[this.state.date]) === null || _this$modelStatus2 === void 0 ? void 0 : _this$modelStatus2[this.state.run]) || [],
|
|
125
125
|
availableVariables: this.getAvailableVariables(this.state.isMRMS ? 'mrms' : this.state.model),
|
|
126
|
+
// We need to confirm this line is working as expected.
|
|
127
|
+
availableMRMSVariables: this.getAvailableVariables('mrms'),
|
|
126
128
|
availableTimestamps: availableTimestamps,
|
|
127
129
|
isPlaying: this.isPlaying,
|
|
128
130
|
colormap: displayColormap,
|
|
129
131
|
colormapBaseUnit: toUnit
|
|
130
|
-
}
|
|
132
|
+
};
|
|
133
|
+
this.emit('state:change', eventPayload);
|
|
131
134
|
}
|
|
132
135
|
async initialize(options = {}) {
|
|
133
136
|
await this.fetchModelStatus(true);
|
|
@@ -379,7 +382,16 @@ class AguaceroCore extends _events.EventEmitter {
|
|
|
379
382
|
return this.dataCache.get(dataUrlIdentifier);
|
|
380
383
|
}
|
|
381
384
|
|
|
382
|
-
//
|
|
385
|
+
// --- EDITED ---
|
|
386
|
+
// If we are in React Native, this function should NOT do any work.
|
|
387
|
+
// The native WeatherFrameProcessorModule is now responsible for all data loading.
|
|
388
|
+
// This function might still be called by a "cache miss" fallback, but it
|
|
389
|
+
// should not fetch data from JS anymore. We return null so the fallback knows
|
|
390
|
+
// that the native module is the only source of truth for new data.
|
|
391
|
+
if (this.isReactNative) {
|
|
392
|
+
console.warn(`_loadGridData was called in React Native for ${dataUrlIdentifier}. This should be handled by the native module. Returning null.`);
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
383
395
|
const abortController = new AbortController();
|
|
384
396
|
this.abortControllers.set(dataUrlIdentifier, abortController);
|
|
385
397
|
const loadPromise = (async () => {
|
|
@@ -388,21 +400,13 @@ class AguaceroCore extends _events.EventEmitter {
|
|
|
388
400
|
}
|
|
389
401
|
try {
|
|
390
402
|
const baseUrl = `${this.baseGridUrl}${resourcePath}`;
|
|
391
|
-
|
|
392
|
-
// NEW: Construct the URL with the apiKey as a query parameter
|
|
393
403
|
const urlWithApiKeyParam = `${baseUrl}?apiKey=${this.apiKey}`;
|
|
394
|
-
|
|
395
|
-
// --- END OF MODIFICATION ---
|
|
396
|
-
|
|
397
|
-
// The headers object remains the same, sending the key in the header as well
|
|
398
404
|
const headers = {
|
|
399
405
|
'x-api-key': this.apiKey
|
|
400
406
|
};
|
|
401
407
|
if (this.bundleId) {
|
|
402
408
|
headers['x-app-identifier'] = this.bundleId;
|
|
403
409
|
}
|
|
404
|
-
|
|
405
|
-
// Use the NEW url variable in the fetch call
|
|
406
410
|
const response = await fetch(urlWithApiKeyParam, {
|
|
407
411
|
headers: headers,
|
|
408
412
|
signal: abortController.signal
|
|
@@ -415,33 +419,27 @@ class AguaceroCore extends _events.EventEmitter {
|
|
|
415
419
|
encoding
|
|
416
420
|
} = await response.json();
|
|
417
421
|
const compressedData = Uint8Array.from(atob(b64Data), c => c.charCodeAt(0));
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
this.workerResolvers.set(requestId, {
|
|
426
|
-
resolve,
|
|
427
|
-
reject
|
|
428
|
-
});
|
|
422
|
+
|
|
423
|
+
// This path is now ONLY for the web worker
|
|
424
|
+
const requestId = this.workerRequestId++;
|
|
425
|
+
const workerPromise = new Promise((resolve, reject) => {
|
|
426
|
+
this.workerResolvers.set(requestId, {
|
|
427
|
+
resolve,
|
|
428
|
+
reject
|
|
429
429
|
});
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
430
|
+
});
|
|
431
|
+
this.worker.postMessage({
|
|
432
|
+
requestId,
|
|
433
|
+
compressedData,
|
|
434
|
+
encoding
|
|
435
|
+
}, [compressedData.buffer]);
|
|
436
|
+
const result = await workerPromise;
|
|
437
|
+
const finalData = result.data;
|
|
438
438
|
const transformedData = new Uint8Array(finalData.length);
|
|
439
439
|
for (let i = 0; i < finalData.length; i++) {
|
|
440
440
|
const signedValue = finalData[i] > 127 ? finalData[i] - 256 : finalData[i];
|
|
441
441
|
transformedData[i] = signedValue + 128;
|
|
442
442
|
}
|
|
443
|
-
|
|
444
|
-
// Clean up abort controller on success
|
|
445
443
|
this.abortControllers.delete(dataUrlIdentifier);
|
|
446
444
|
return {
|
|
447
445
|
data: transformedData,
|
|
@@ -550,6 +548,9 @@ class AguaceroCore extends _events.EventEmitter {
|
|
|
550
548
|
colormap: [],
|
|
551
549
|
baseUnit: ''
|
|
552
550
|
};
|
|
551
|
+
|
|
552
|
+
// This logic for user-provided custom colormaps is correct.
|
|
553
|
+
// If a user provides a custom map, it should always take top priority.
|
|
553
554
|
if (this.customColormaps[variable] && this.customColormaps[variable].colormap) {
|
|
554
555
|
return {
|
|
555
556
|
colormap: this.customColormaps[variable].colormap,
|
|
@@ -565,19 +566,45 @@ class AguaceroCore extends _events.EventEmitter {
|
|
|
565
566
|
};
|
|
566
567
|
}
|
|
567
568
|
const defaultColormapData = _defaultColormaps.DEFAULT_COLORMAPS[colormapKey];
|
|
569
|
+
|
|
570
|
+
// --- START OF THE BUG FIX ---
|
|
571
|
+
// This block handles the "default" case when no custom colormap is provided.
|
|
568
572
|
if (defaultColormapData && defaultColormapData.units) {
|
|
573
|
+
var _DICTIONARIES$fld$var;
|
|
574
|
+
// 1. EDITED: Explicitly look up the CORRECT default unit from the main dictionary.
|
|
575
|
+
// This is the information source we were previously ignoring.
|
|
576
|
+
const preferredUnit = (_DICTIONARIES$fld$var = _dictionaries.DICTIONARIES.fld[variable]) === null || _DICTIONARIES$fld$var === void 0 ? void 0 : _DICTIONARIES$fld$var.defaultUnit; // e.g., '°C' for '2t_2'
|
|
577
|
+
|
|
578
|
+
// 2. EDITED: Check if that preferred unit exists in the colormap definitions.
|
|
579
|
+
if (preferredUnit && defaultColormapData.units[preferredUnit]) {
|
|
580
|
+
const unitData = defaultColormapData.units[preferredUnit];
|
|
581
|
+
if (unitData && unitData.colormap) {
|
|
582
|
+
// 3. EDITED: If it exists, return ITS data. This is the correct path.
|
|
583
|
+
console.log(`[AguaceroCore] Using dictionary default unit '${preferredUnit}' for variable '${variable}'.`);
|
|
584
|
+
return {
|
|
585
|
+
colormap: unitData.colormap,
|
|
586
|
+
baseUnit: preferredUnit
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// 4. EDITED: The old, buggy logic now serves as a FALLBACK ONLY.
|
|
592
|
+
// This will only run if the specified defaultUnit is missing from the colormap data.
|
|
593
|
+
console.warn(`[AguaceroCore] Default unit for '${variable}' not found in colormap. Using fallback.`);
|
|
569
594
|
const availableUnits = Object.keys(defaultColormapData.units);
|
|
570
595
|
if (availableUnits.length > 0) {
|
|
571
|
-
const
|
|
572
|
-
const unitData = defaultColormapData.units[
|
|
596
|
+
const fallbackUnit = availableUnits[0]; // e.g., '°F'
|
|
597
|
+
const unitData = defaultColormapData.units[fallbackUnit];
|
|
573
598
|
if (unitData && unitData.colormap) {
|
|
574
599
|
return {
|
|
575
600
|
colormap: unitData.colormap,
|
|
576
|
-
baseUnit:
|
|
601
|
+
baseUnit: fallbackUnit
|
|
577
602
|
};
|
|
578
603
|
}
|
|
579
604
|
}
|
|
580
605
|
}
|
|
606
|
+
// --- END OF THE BUG FIX ---
|
|
607
|
+
|
|
581
608
|
return {
|
|
582
609
|
colormap: [],
|
|
583
610
|
baseUnit: ''
|
package/dist/dictionaries.js
CHANGED
|
@@ -218,7 +218,7 @@ const MODEL_CONFIGS = exports.MODEL_CONFIGS = {
|
|
|
218
218
|
},
|
|
219
219
|
'gfs': {
|
|
220
220
|
max_zoom: 3,
|
|
221
|
-
vars: ['refd_1000', 'vis_0', 'gust_runmax', "gh_tendency_500", 'bulk_shear_speedmb_500', 'bulk_shear_speedmb_700', 'bulk_shear_speedmb_850', 'bulk_shear_speedmb_925', '2t_2iso0', 'crain_total', 'crain_3', 'crain_6', 'crain_12', 'crain_24', 'crain_48', 'cicep_total', 'cicep_3', 'cicep_6', 'cicep_12', 'cicep_24', 'cicep_48', 'cfrzr_total', 'cfrzr_3', 'cfrzr_6', 'cfrzr_12', 'cfrzr_24', 'cfrzr_48', 'csnow_total', 'csnow_3', 'csnow_6', 'csnow_12', 'csnow_24', 'csnow_48', 'tp_0_total', 'tp_3', 'tp_6', 'tp_12', 'tp_24', 'tp_48', 'cin_0', 'wind_speed_700', 'wind_speed_200', 'divergence_200', 'd_925', 'tadv_300', 'w_850', 'rainRefl', 'icepRefl', 'snowRefl', 'frzrRefl', '
|
|
221
|
+
vars: ['2r_2', '2t_2', 'refd_1000', 'vis_0', 'gust_runmax', "gh_tendency_500", 'bulk_shear_speedmb_500', 'bulk_shear_speedmb_700', 'bulk_shear_speedmb_850', 'bulk_shear_speedmb_925', '2t_2iso0', 'crain_total', 'crain_3', 'crain_6', 'crain_12', 'crain_24', 'crain_48', 'cicep_total', 'cicep_3', 'cicep_6', 'cicep_12', 'cicep_24', 'cicep_48', 'cfrzr_total', 'cfrzr_3', 'cfrzr_6', 'cfrzr_12', 'cfrzr_24', 'cfrzr_48', 'csnow_total', 'csnow_3', 'csnow_6', 'csnow_12', 'csnow_24', 'csnow_48', 'tp_0_total', 'tp_3', 'tp_6', 'tp_12', 'tp_24', 'tp_48', 'cin_0', 'wind_speed_700', 'wind_speed_200', 'divergence_200', 'd_925', 'tadv_300', 'w_850', 'rainRefl', 'icepRefl', 'snowRefl', 'frzrRefl', 'lftx_0', 'refc_0', 'fgen_850', 'hcc_0', 'r_700', 't_850', 't_850iso0', 'r_850', 'tcc_0', 'hlcy_3000', 'thickness', 'vo_850', 'wind_direction_2000', 'r_500', 'gh_500', 'wind_speed_500', '2d_2', 'cape_25500', 'mcc_0', 'w_500', 'pwat_0', 'divergence_850', 't_500', 'wind_speed_850', 'lcl', 'cape_0', 'tadv_850', 'tadv_700', 'theta2PVU', 'wind_speed_2000', 'lapse_rates_500700', 'vo_500', 'irsat', 't_700', 't_700iso0', 'cin_25500', 'ehi_3000', 'lcc_0', 'gh_850', 'wind_speed_925', 'gh_200', 'wind_speed_300', 'fgen_700', 'vo_700', 'd_850', 'thetaE', 'pres2PVU', 'd_700', 'crain', 'csnow', 'cicep', 'cfrzr', 'w_700', 'gust_0', 'ivt', 'atemp', 'cape_9000', 'r_925', 'mslma_0', 'w_925', 'cin_9000', 'mean700300mbRH', 'wind_speed_10', 't_925', 't_925iso0', 'gh_925', 'gh_700', 'gh_300'],
|
|
222
222
|
category: 'Global',
|
|
223
223
|
name: 'GFS',
|
|
224
224
|
bounds: [-180, -90, 180, 90],
|
package/dist/events.js
CHANGED
|
@@ -17,8 +17,18 @@ class EventEmitter {
|
|
|
17
17
|
if (!this.callbacks[event]) this.callbacks[event] = [];
|
|
18
18
|
this.callbacks[event].push(cb);
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
// --- THIS IS THE MISSING PIECE ---
|
|
22
|
+
// Add this method to allow listeners to be removed.
|
|
23
|
+
off(event, cb) {
|
|
24
|
+
const cbs = this.callbacks[event];
|
|
25
|
+
if (cbs) {
|
|
26
|
+
// Create a new array that excludes the callback we want to remove
|
|
27
|
+
this.callbacks[event] = cbs.filter(callback => callback !== cb);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
20
30
|
emit(event, data) {
|
|
21
|
-
|
|
31
|
+
const cbs = this.callbacks[event];
|
|
22
32
|
if (cbs) {
|
|
23
33
|
cbs.forEach(cb => cb(data));
|
|
24
34
|
}
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,20 @@ Object.defineProperty(exports, "THEME_CONFIGS", {
|
|
|
27
27
|
return _mapStyles.THEME_CONFIGS;
|
|
28
28
|
}
|
|
29
29
|
});
|
|
30
|
+
Object.defineProperty(exports, "getUnitConversionFunction", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _unitConversions.getUnitConversionFunction;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "unitConversions", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _unitConversions.unitConversions;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
30
42
|
var _AguaceroCore = require("./AguaceroCore.js");
|
|
31
43
|
var _events = require("./events.js");
|
|
32
44
|
var _mapStyles = require("./map-styles.js");
|
|
33
|
-
var _dictionaries = require("./dictionaries.js");
|
|
45
|
+
var _dictionaries = require("./dictionaries.js");
|
|
46
|
+
var _unitConversions = require("./unitConversions.js");
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aguacerowx/javascript-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"description": "Core SDK for fetching and processing Aguacero weather data.",
|
|
9
|
-
"main": "
|
|
9
|
+
"main": "src/index.js",
|
|
10
10
|
"module": "src/index.js",
|
|
11
|
-
"react-native": "
|
|
11
|
+
"react-native": "src/index.js",
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
14
14
|
"import": "./src/index.js",
|
|
15
|
-
"require": "./
|
|
16
|
-
"react-native": "./
|
|
15
|
+
"require": "./src/index.js",
|
|
16
|
+
"react-native": "./src/index.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
@@ -45,4 +45,4 @@
|
|
|
45
45
|
"optional": true
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
}
|
|
48
|
+
}
|
package/src/AguaceroCore.js
CHANGED
|
@@ -81,7 +81,7 @@ export class AguaceroCore extends EventEmitter {
|
|
|
81
81
|
run: null,
|
|
82
82
|
forecastHour: 0,
|
|
83
83
|
visible: true,
|
|
84
|
-
opacity: userLayerOptions.opacity ??
|
|
84
|
+
opacity: userLayerOptions.opacity ?? 1,
|
|
85
85
|
units: options.initialUnit || 'imperial',
|
|
86
86
|
shaderSmoothingEnabled: options.shaderSmoothingEnabled ?? true
|
|
87
87
|
};
|
|
@@ -107,17 +107,21 @@ export class AguaceroCore extends EventEmitter {
|
|
|
107
107
|
availableTimestamps = [...timestamps].reverse();
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
const eventPayload = {
|
|
111
111
|
...this.state,
|
|
112
112
|
availableModels: this.modelStatus ? Object.keys(this.modelStatus).sort() : [],
|
|
113
113
|
availableRuns: this.modelStatus?.[this.state.model] || {},
|
|
114
114
|
availableHours: this.state.isMRMS ? [] : (this.modelStatus?.[this.state.model]?.[this.state.date]?.[this.state.run] || []),
|
|
115
115
|
availableVariables: this.getAvailableVariables(this.state.isMRMS ? 'mrms' : this.state.model),
|
|
116
|
+
// We need to confirm this line is working as expected.
|
|
117
|
+
availableMRMSVariables: this.getAvailableVariables('mrms'),
|
|
116
118
|
availableTimestamps: availableTimestamps,
|
|
117
119
|
isPlaying: this.isPlaying,
|
|
118
120
|
colormap: displayColormap,
|
|
119
121
|
colormapBaseUnit: toUnit,
|
|
120
|
-
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
this.emit('state:change', eventPayload);
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
async initialize(options = {}) {
|
|
@@ -312,6 +316,10 @@ export class AguaceroCore extends EventEmitter {
|
|
|
312
316
|
}
|
|
313
317
|
|
|
314
318
|
async _loadGridData(state) {
|
|
319
|
+
if (this.isReactNative) {
|
|
320
|
+
console.warn(`[AguaceroCore] _loadGridData was called in React Native. This is a bypass. Data loading is handled natively.`);
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
315
323
|
const { model, date, run, forecastHour, variable, isMRMS, mrmsTimestamp } = state;
|
|
316
324
|
let effectiveSmoothing = 0;
|
|
317
325
|
const customVariableSettings = this.customColormaps[variable];
|
|
@@ -334,30 +342,32 @@ export class AguaceroCore extends EventEmitter {
|
|
|
334
342
|
return this.dataCache.get(dataUrlIdentifier);
|
|
335
343
|
}
|
|
336
344
|
|
|
337
|
-
//
|
|
345
|
+
// --- EDITED ---
|
|
346
|
+
// If we are in React Native, this function should NOT do any work.
|
|
347
|
+
// The native WeatherFrameProcessorModule is now responsible for all data loading.
|
|
348
|
+
// This function might still be called by a "cache miss" fallback, but it
|
|
349
|
+
// should not fetch data from JS anymore. We return null so the fallback knows
|
|
350
|
+
// that the native module is the only source of truth for new data.
|
|
351
|
+
if (this.isReactNative) {
|
|
352
|
+
console.warn(`_loadGridData was called in React Native for ${dataUrlIdentifier}. This should be handled by the native module. Returning null.`);
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
|
|
338
356
|
const abortController = new AbortController();
|
|
339
357
|
this.abortControllers.set(dataUrlIdentifier, abortController);
|
|
340
|
-
|
|
358
|
+
|
|
341
359
|
const loadPromise = (async () => {
|
|
342
360
|
if (!this.apiKey) {
|
|
343
361
|
throw new Error('API key is not configured.');
|
|
344
362
|
}
|
|
345
363
|
try {
|
|
346
364
|
const baseUrl = `${this.baseGridUrl}${resourcePath}`;
|
|
347
|
-
|
|
348
|
-
// NEW: Construct the URL with the apiKey as a query parameter
|
|
349
365
|
const urlWithApiKeyParam = `${baseUrl}?apiKey=${this.apiKey}`;
|
|
350
|
-
|
|
351
|
-
// --- END OF MODIFICATION ---
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
// The headers object remains the same, sending the key in the header as well
|
|
355
366
|
const headers = { 'x-api-key': this.apiKey };
|
|
356
367
|
if (this.bundleId) {
|
|
357
368
|
headers['x-app-identifier'] = this.bundleId;
|
|
358
369
|
}
|
|
359
370
|
|
|
360
|
-
// Use the NEW url variable in the fetch call
|
|
361
371
|
const response = await fetch(urlWithApiKeyParam, {
|
|
362
372
|
headers: headers,
|
|
363
373
|
signal: abortController.signal
|
|
@@ -369,20 +379,14 @@ export class AguaceroCore extends EventEmitter {
|
|
|
369
379
|
const { data: b64Data, encoding } = await response.json();
|
|
370
380
|
const compressedData = Uint8Array.from(atob(b64Data), c => c.charCodeAt(0));
|
|
371
381
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
this.workerResolvers.set(requestId, { resolve, reject });
|
|
381
|
-
});
|
|
382
|
-
this.worker.postMessage({ requestId, compressedData, encoding }, [compressedData.buffer]);
|
|
383
|
-
const result = await workerPromise;
|
|
384
|
-
finalData = result.data;
|
|
385
|
-
}
|
|
382
|
+
// This path is now ONLY for the web worker
|
|
383
|
+
const requestId = this.workerRequestId++;
|
|
384
|
+
const workerPromise = new Promise((resolve, reject) => {
|
|
385
|
+
this.workerResolvers.set(requestId, { resolve, reject });
|
|
386
|
+
});
|
|
387
|
+
this.worker.postMessage({ requestId, compressedData, encoding }, [compressedData.buffer]);
|
|
388
|
+
const result = await workerPromise;
|
|
389
|
+
const finalData = result.data;
|
|
386
390
|
|
|
387
391
|
const transformedData = new Uint8Array(finalData.length);
|
|
388
392
|
for (let i = 0; i < finalData.length; i++) {
|
|
@@ -390,7 +394,6 @@ export class AguaceroCore extends EventEmitter {
|
|
|
390
394
|
transformedData[i] = signedValue + 128;
|
|
391
395
|
}
|
|
392
396
|
|
|
393
|
-
// Clean up abort controller on success
|
|
394
397
|
this.abortControllers.delete(dataUrlIdentifier);
|
|
395
398
|
|
|
396
399
|
return { data: transformedData, encoding };
|
|
@@ -570,13 +573,15 @@ export class AguaceroCore extends EventEmitter {
|
|
|
570
573
|
|
|
571
574
|
_getTargetUnit(defaultUnit, system) {
|
|
572
575
|
if (system === 'metric') {
|
|
573
|
-
if (['°F', '°C'].includes(defaultUnit)) return '
|
|
576
|
+
if (['°F', '°C', 'fahrenheit', 'celsius'].includes(defaultUnit)) return '°C';
|
|
574
577
|
if (['kts', 'mph', 'm/s'].includes(defaultUnit)) return 'km/h';
|
|
575
578
|
if (['in', 'mm', 'cm'].includes(defaultUnit)) return 'mm';
|
|
576
579
|
}
|
|
577
|
-
if (
|
|
578
|
-
|
|
579
|
-
|
|
580
|
+
if (system === 'imperial') {
|
|
581
|
+
if (['°F', '°C', 'fahrenheit', 'celsius'].includes(defaultUnit)) return '°F';
|
|
582
|
+
if (['kts', 'mph', 'm/s'].includes(defaultUnit)) return 'mph';
|
|
583
|
+
if (['in', 'mm', 'cm'].includes(defaultUnit)) return 'in';
|
|
584
|
+
}
|
|
580
585
|
return defaultUnit;
|
|
581
586
|
}
|
|
582
587
|
|
package/src/dictionaries.js
CHANGED
|
@@ -278,7 +278,7 @@ export const MODEL_CONFIGS = {
|
|
|
278
278
|
},
|
|
279
279
|
'gfs': {
|
|
280
280
|
max_zoom: 3,
|
|
281
|
-
vars: ['refd_1000', 'vis_0', 'gust_runmax', "gh_tendency_500", 'bulk_shear_speedmb_500', 'bulk_shear_speedmb_700', 'bulk_shear_speedmb_850', 'bulk_shear_speedmb_925','2t_2iso0', 'crain_total', 'crain_3', 'crain_6', 'crain_12', 'crain_24', 'crain_48', 'cicep_total', 'cicep_3', 'cicep_6', 'cicep_12', 'cicep_24', 'cicep_48', 'cfrzr_total', 'cfrzr_3', 'cfrzr_6', 'cfrzr_12', 'cfrzr_24', 'cfrzr_48', 'csnow_total', 'csnow_3', 'csnow_6', 'csnow_12', 'csnow_24', 'csnow_48', 'tp_0_total', 'tp_3', 'tp_6', 'tp_12', 'tp_24', 'tp_48', 'cin_0', 'wind_speed_700', 'wind_speed_200', 'divergence_200', 'd_925', 'tadv_300', 'w_850', 'rainRefl', 'icepRefl', 'snowRefl', 'frzrRefl', '
|
|
281
|
+
vars: ['2r_2', '2t_2', 'refd_1000', 'vis_0', 'gust_runmax', "gh_tendency_500", 'bulk_shear_speedmb_500', 'bulk_shear_speedmb_700', 'bulk_shear_speedmb_850', 'bulk_shear_speedmb_925','2t_2iso0', 'crain_total', 'crain_3', 'crain_6', 'crain_12', 'crain_24', 'crain_48', 'cicep_total', 'cicep_3', 'cicep_6', 'cicep_12', 'cicep_24', 'cicep_48', 'cfrzr_total', 'cfrzr_3', 'cfrzr_6', 'cfrzr_12', 'cfrzr_24', 'cfrzr_48', 'csnow_total', 'csnow_3', 'csnow_6', 'csnow_12', 'csnow_24', 'csnow_48', 'tp_0_total', 'tp_3', 'tp_6', 'tp_12', 'tp_24', 'tp_48', 'cin_0', 'wind_speed_700', 'wind_speed_200', 'divergence_200', 'd_925', 'tadv_300', 'w_850', 'rainRefl', 'icepRefl', 'snowRefl', 'frzrRefl', 'lftx_0', 'refc_0', 'fgen_850', 'hcc_0', 'r_700', 't_850', 't_850iso0', 'r_850', 'tcc_0', 'hlcy_3000', 'thickness', 'vo_850', 'wind_direction_2000', 'r_500', 'gh_500', 'wind_speed_500', '2d_2', 'cape_25500', 'mcc_0', 'w_500', 'pwat_0', 'divergence_850', 't_500', 'wind_speed_850', 'lcl', 'cape_0', 'tadv_850', 'tadv_700', 'theta2PVU', 'wind_speed_2000', 'lapse_rates_500700', 'vo_500', 'irsat', 't_700', 't_700iso0', 'cin_25500', 'ehi_3000', 'lcc_0', 'gh_850', 'wind_speed_925', 'gh_200', 'wind_speed_300', 'fgen_700', 'vo_700', 'd_850', 'thetaE', 'pres2PVU', 'd_700', 'crain', 'csnow', 'cicep', 'cfrzr', 'w_700', 'gust_0', 'ivt', 'atemp', 'cape_9000', 'r_925', 'mslma_0', 'w_925', 'cin_9000', 'mean700300mbRH', 'wind_speed_10', 't_925', 't_925iso0', 'gh_925', 'gh_700', 'gh_300'],
|
|
282
282
|
category: 'Global',
|
|
283
283
|
name: 'GFS',
|
|
284
284
|
bounds: [-180, -90, 180, 90],
|
package/src/events.js
CHANGED
|
@@ -7,12 +7,24 @@ export class EventEmitter {
|
|
|
7
7
|
constructor() {
|
|
8
8
|
this.callbacks = {};
|
|
9
9
|
}
|
|
10
|
+
|
|
10
11
|
on(event, cb) {
|
|
11
12
|
if (!this.callbacks[event]) this.callbacks[event] = [];
|
|
12
13
|
this.callbacks[event].push(cb);
|
|
13
14
|
}
|
|
15
|
+
|
|
16
|
+
// --- THIS IS THE MISSING PIECE ---
|
|
17
|
+
// Add this method to allow listeners to be removed.
|
|
18
|
+
off(event, cb) {
|
|
19
|
+
const cbs = this.callbacks[event];
|
|
20
|
+
if (cbs) {
|
|
21
|
+
// Create a new array that excludes the callback we want to remove
|
|
22
|
+
this.callbacks[event] = cbs.filter(callback => callback !== cb);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
14
26
|
emit(event, data) {
|
|
15
|
-
|
|
27
|
+
const cbs = this.callbacks[event];
|
|
16
28
|
if (cbs) {
|
|
17
29
|
cbs.forEach(cb => cb(data));
|
|
18
30
|
}
|
package/src/index.js
CHANGED
|
@@ -5,11 +5,13 @@ import { AguaceroCore } from './AguaceroCore.js';
|
|
|
5
5
|
import { EventEmitter } from './events.js';
|
|
6
6
|
import { THEME_CONFIGS } from './map-styles.js';
|
|
7
7
|
import { DICTIONARIES } from './dictionaries.js';
|
|
8
|
+
import { getUnitConversionFunction } from './unitConversions.js';
|
|
8
9
|
|
|
9
10
|
// Now, export them all so other packages can import them.
|
|
10
11
|
export {
|
|
11
12
|
AguaceroCore,
|
|
12
13
|
EventEmitter,
|
|
13
14
|
THEME_CONFIGS,
|
|
14
|
-
DICTIONARIES
|
|
15
|
+
DICTIONARIES,
|
|
16
|
+
getUnitConversionFunction
|
|
15
17
|
};
|