@aguacerowx/mapsgl 0.0.29 → 0.0.32
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/package.json +1 -1
- package/src/WeatherLayerManager.js +29 -74
package/package.json
CHANGED
|
@@ -69,26 +69,14 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
69
69
|
const runKey = `${state.model}-${state.date}-${state.run}-${state.variable}`;
|
|
70
70
|
const existingRunKey = this.shaderLayer?.runKey ?? 'none';
|
|
71
71
|
|
|
72
|
-
console.log(`[WLM._handleStateChange]`, {
|
|
73
|
-
runKey, timeKey,
|
|
74
|
-
existingRunKey,
|
|
75
|
-
currentLoadedTimeKey: this.currentLoadedTimeKey,
|
|
76
|
-
shaderLayerExists: !!this.shaderLayer,
|
|
77
|
-
decision: !this.shaderLayer || existingRunKey !== runKey
|
|
78
|
-
? 'REBUILD'
|
|
79
|
-
: this.currentLoadedTimeKey !== timeKey
|
|
80
|
-
? 'UPDATE_DATA'
|
|
81
|
-
: 'STYLE_ONLY'
|
|
82
|
-
});
|
|
83
|
-
|
|
84
72
|
if (!this.shaderLayer || this.shaderLayer.runKey !== runKey) {
|
|
85
|
-
console.log(`[WLM._handleStateChange] → dispatching _rebuildLayerAndPreload (runKey changed: "${existingRunKey}" → "${runKey}")`);
|
|
73
|
+
//console.log(`[WLM._handleStateChange] → dispatching _rebuildLayerAndPreload (runKey changed: "${existingRunKey}" → "${runKey}")`);
|
|
86
74
|
this._rebuildLayerAndPreload(state);
|
|
87
75
|
} else if (this.currentLoadedTimeKey !== timeKey) {
|
|
88
|
-
console.log(`[WLM._handleStateChange] → dispatching _updateLayerData (timeKey changed: ${this.currentLoadedTimeKey} → ${timeKey})`);
|
|
76
|
+
//console.log(`[WLM._handleStateChange] → dispatching _updateLayerData (timeKey changed: ${this.currentLoadedTimeKey} → ${timeKey})`);
|
|
89
77
|
this._updateLayerData(state);
|
|
90
78
|
} else {
|
|
91
|
-
console.log(`[WLM._handleStateChange] → style/opacity update only`);
|
|
79
|
+
//console.log(`[WLM._handleStateChange] → style/opacity update only`);
|
|
92
80
|
}
|
|
93
81
|
|
|
94
82
|
if (this.shaderLayer) {
|
|
@@ -140,30 +128,30 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
140
128
|
}
|
|
141
129
|
|
|
142
130
|
const timeKey = state.isMRMS ? state.mrmsTimestamp : state.forecastHour;
|
|
143
|
-
console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} timeKey=${timeKey}`);
|
|
131
|
+
//console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} timeKey=${timeKey}`);
|
|
144
132
|
|
|
145
133
|
if (this.shaderLayer.switchToPreloadedTexture(timeKey)) {
|
|
146
134
|
this.currentLoadedTimeKey = timeKey;
|
|
147
|
-
console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — FAST PATH: preloaded texture found for timeKey=${timeKey}, swapped instantly`);
|
|
135
|
+
//console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — FAST PATH: preloaded texture found for timeKey=${timeKey}, swapped instantly`);
|
|
148
136
|
this.map.triggerRepaint();
|
|
149
137
|
return;
|
|
150
138
|
}
|
|
151
139
|
|
|
152
|
-
console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — SLOW PATH: no preloaded texture for timeKey=${timeKey}, fetching...`);
|
|
140
|
+
//console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — SLOW PATH: no preloaded texture for timeKey=${timeKey}, fetching...`);
|
|
153
141
|
const fetchStart = performance.now();
|
|
154
142
|
try {
|
|
155
143
|
const grid = await this.core._loadGridData(state);
|
|
156
144
|
const fetchMs = (performance.now() - fetchStart).toFixed(1);
|
|
157
145
|
|
|
158
146
|
if (requestToken !== this.latestDataRequestToken) {
|
|
159
|
-
console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — STALE after fetch (latestToken=${this.latestDataRequestToken}), discarding (${fetchMs}ms)`);
|
|
147
|
+
//console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — STALE after fetch (latestToken=${this.latestDataRequestToken}), discarding (${fetchMs}ms)`);
|
|
160
148
|
return;
|
|
161
149
|
}
|
|
162
150
|
|
|
163
151
|
if (grid && grid.data) {
|
|
164
152
|
const gridModel = state.isMRMS ? 'mrms' : state.model;
|
|
165
153
|
const { gridDef } = this.core._getGridCornersAndDef(gridModel);
|
|
166
|
-
console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — grid received in ${fetchMs}ms, storing+switching texture for timeKey=${timeKey}`);
|
|
154
|
+
//console.log(`[WLM._updateLayerDataWithToken] token=${requestToken} — grid received in ${fetchMs}ms, storing+switching texture for timeKey=${timeKey}`);
|
|
167
155
|
|
|
168
156
|
this.shaderLayer.storePreloadedTexture(
|
|
169
157
|
timeKey, grid.data, grid.encoding,
|
|
@@ -189,28 +177,17 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
189
177
|
|
|
190
178
|
async _rebuildLayerAndPreload(state) {
|
|
191
179
|
const rebuildId = ++this.currentRebuildId;
|
|
192
|
-
console.log(`[WLM._rebuildLayerAndPreload] START rebuildId=${rebuildId}`, {
|
|
193
|
-
model: state.model, variable: state.variable, date: state.date,
|
|
194
|
-
run: state.run, forecastHour: state.forecastHour,
|
|
195
|
-
isMRMS: state.isMRMS, mrmsTimestamp: state.mrmsTimestamp
|
|
196
|
-
});
|
|
197
180
|
|
|
198
181
|
this.core.cancelAllRequests();
|
|
199
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — cancelled all pending requests`);
|
|
200
182
|
|
|
201
183
|
if (this.shaderLayer) {
|
|
202
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — removing existing shaderLayer id=${this.shaderLayer.id} runKey=${this.shaderLayer.runKey}`);
|
|
203
184
|
this.map.removeLayer(this.shaderLayer.id);
|
|
204
185
|
this.shaderLayer = null;
|
|
205
186
|
}
|
|
206
187
|
this.currentLoadedTimeKey = null;
|
|
207
188
|
|
|
208
|
-
if (!state.variable)
|
|
209
|
-
console.warn(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — no variable set, aborting rebuild`);
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
189
|
+
if (!state.variable) return;
|
|
212
190
|
|
|
213
|
-
// --- FIX: Correct an invalid forecastHour before building the layer ---
|
|
214
191
|
if (
|
|
215
192
|
!state.isMRMS &&
|
|
216
193
|
state.forecastHour === 0 &&
|
|
@@ -220,50 +197,32 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
220
197
|
const availableHours =
|
|
221
198
|
this.core.modelStatus?.[state.model]?.[state.date]?.[state.run] || [];
|
|
222
199
|
const firstValidHour = availableHours.find(h => h !== 0);
|
|
223
|
-
console.warn(
|
|
224
|
-
`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — ptypeRefl/HRRR hour-0 correction triggered.`,
|
|
225
|
-
{ availableHours, firstValidHour: firstValidHour ?? 'NOT FOUND — will proceed with 0' }
|
|
226
|
-
);
|
|
227
200
|
if (firstValidHour !== undefined) {
|
|
228
201
|
state = { ...state, forecastHour: firstValidHour };
|
|
229
|
-
// CRITICAL: Mutate core.state directly instead of calling core.setState().
|
|
230
|
-
// core.setState() emits state:change, which triggers _handleStateChange,
|
|
231
|
-
// which spawns a second concurrent rebuild — causing a duplicate addLayer
|
|
232
|
-
// crash and a gl=null texture upload on the layer that wins the race.
|
|
233
202
|
this.core.state.forecastHour = firstValidHour;
|
|
234
|
-
|
|
203
|
+
} else {
|
|
204
|
+
// Run exists but has no valid hours yet — bail out entirely
|
|
205
|
+
console.warn(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — ptypeRefl/HRRR: no valid hours in new run yet, aborting rebuild`);
|
|
206
|
+
return;
|
|
235
207
|
}
|
|
236
208
|
}
|
|
237
|
-
// --- END FIX ---
|
|
238
209
|
|
|
239
|
-
|
|
240
|
-
if (rebuildId !== this.currentRebuildId) {
|
|
241
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — STALE before addLayer (currentRebuildId=${this.currentRebuildId}), aborting`);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
210
|
+
if (rebuildId !== this.currentRebuildId) return;
|
|
244
211
|
|
|
245
212
|
const runKey = `${state.model}-${state.date}-${state.run}-${state.variable}`;
|
|
246
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — creating shaderLayer runKey=${runKey}, forecastHour=${state.forecastHour}`);
|
|
247
213
|
|
|
248
214
|
this.shaderLayer = new GridRenderLayer(this.layerId);
|
|
249
215
|
this.shaderLayer.runKey = runKey;
|
|
250
216
|
this.map.addLayer(this.shaderLayer, 'AML_-_terrain');
|
|
251
217
|
this._updateLayerStyle(state);
|
|
252
218
|
|
|
253
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — fetching grid data...`);
|
|
254
|
-
const fetchStart = performance.now();
|
|
255
219
|
const grid = await this.core._loadGridData(state);
|
|
256
|
-
const fetchMs = (performance.now() - fetchStart).toFixed(1);
|
|
257
220
|
|
|
258
|
-
if (rebuildId !== this.currentRebuildId)
|
|
259
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — STALE after grid fetch (currentRebuildId=${this.currentRebuildId}), discarding result (fetch took ${fetchMs}ms)`);
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
221
|
+
if (rebuildId !== this.currentRebuildId) return;
|
|
262
222
|
|
|
263
223
|
if (grid && grid.data) {
|
|
264
224
|
const gridModel = state.isMRMS ? 'mrms' : state.model;
|
|
265
225
|
const { gridDef } = this.core._getGridCornersAndDef(gridModel);
|
|
266
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — grid data received in ${fetchMs}ms, uploading texture. nx=${gridDef.grid_params.nx} ny=${gridDef.grid_params.ny} dataLength=${grid.data.length}`);
|
|
267
226
|
|
|
268
227
|
this.shaderLayer.updateDataTexture(
|
|
269
228
|
grid.data, grid.encoding,
|
|
@@ -272,35 +231,25 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
272
231
|
|
|
273
232
|
this.currentLoadedTimeKey = state.isMRMS ? state.mrmsTimestamp : state.forecastHour;
|
|
274
233
|
this.latestDataRequestToken = this.currentRebuildId;
|
|
275
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — texture uploaded, currentLoadedTimeKey=${this.currentLoadedTimeKey}, triggering repaint`);
|
|
276
234
|
this.map.triggerRepaint();
|
|
277
|
-
} else {
|
|
278
|
-
console.error(
|
|
279
|
-
`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — grid fetch returned null/empty after ${fetchMs}ms.`,
|
|
280
|
-
{ model: state.model, variable: state.variable, date: state.date, run: state.run, forecastHour: state.forecastHour, isMRMS: state.isMRMS },
|
|
281
|
-
'← THIS IS WHY THE MAP IS BLANK'
|
|
282
|
-
);
|
|
283
235
|
}
|
|
284
236
|
|
|
285
237
|
if (rebuildId === this.currentRebuildId) {
|
|
286
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — starting preload for all time steps`);
|
|
287
238
|
this._preloadAllTimeSteps(state);
|
|
288
|
-
} else {
|
|
289
|
-
console.log(`[WLM._rebuildLayerAndPreload] rebuildId=${rebuildId} — skipping preload, rebuild superseded by rebuildId=${this.currentRebuildId}`);
|
|
290
239
|
}
|
|
291
240
|
}
|
|
292
241
|
|
|
293
242
|
_preloadAllTimeSteps(state) {
|
|
294
243
|
const timeSteps = state.isMRMS ? state.availableTimestamps : state.availableHours;
|
|
295
244
|
if (!timeSteps || timeSteps.length <= 1) {
|
|
296
|
-
console.log(`[WLM._preloadAllTimeSteps] skipping — only ${timeSteps?.length ?? 0} time steps available`);
|
|
245
|
+
//console.log(`[WLM._preloadAllTimeSteps] skipping — only ${timeSteps?.length ?? 0} time steps available`);
|
|
297
246
|
return;
|
|
298
247
|
}
|
|
299
248
|
|
|
300
249
|
const currentFrameTime = state.isMRMS ? state.mrmsTimestamp : state.forecastHour;
|
|
301
250
|
const stepsToPreload = timeSteps.filter(t => t !== currentFrameTime);
|
|
302
251
|
const capturedRebuildId = this.currentRebuildId;
|
|
303
|
-
console.log(`[WLM._preloadAllTimeSteps] preloading ${stepsToPreload.length} frames (skipping currentFrameTime=${currentFrameTime}), capturedRebuildId=${capturedRebuildId}`);
|
|
252
|
+
//console.log(`[WLM._preloadAllTimeSteps] preloading ${stepsToPreload.length} frames (skipping currentFrameTime=${currentFrameTime}), capturedRebuildId=${capturedRebuildId}`);
|
|
304
253
|
|
|
305
254
|
const gridModel = state.isMRMS ? 'mrms' : state.model;
|
|
306
255
|
const { gridDef } = this.core._getGridCornersAndDef(gridModel);
|
|
@@ -321,7 +270,7 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
321
270
|
gridDef.grid_params.nx, gridDef.grid_params.ny
|
|
322
271
|
);
|
|
323
272
|
completed++;
|
|
324
|
-
console.log(`[WLM._preloadAllTimeSteps] stored texture for time=${time} (${completed}/${stepsToPreload.length} done, ${failed} failed)`);
|
|
273
|
+
//console.log(`[WLM._preloadAllTimeSteps] stored texture for time=${time} (${completed}/${stepsToPreload.length} done, ${failed} failed)`);
|
|
325
274
|
} else if (!grid?.data) {
|
|
326
275
|
failed++;
|
|
327
276
|
console.warn(`[WLM._preloadAllTimeSteps] null grid for time=${time} — skipping texture store (${completed}/${stepsToPreload.length} done, ${failed} failed)`);
|
|
@@ -357,10 +306,10 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
357
306
|
let dataRange;
|
|
358
307
|
if (state.variable === 'ptypeRefl' || state.variable === 'ptypeRate') {
|
|
359
308
|
if (state.isMRMS) {
|
|
360
|
-
console.log('🔧 Using MRMS ptype data range: 5-380');
|
|
309
|
+
//console.log('🔧 Using MRMS ptype data range: 5-380');
|
|
361
310
|
dataRange = [5, 380];
|
|
362
311
|
} else {
|
|
363
|
-
console.log('🔧 Using Model ptype data range: 5-380');
|
|
312
|
+
//console.log('🔧 Using Model ptype data range: 5-380');
|
|
364
313
|
dataRange = [5, 380]; // Models also use the full colormap range
|
|
365
314
|
}
|
|
366
315
|
} else {
|
|
@@ -432,7 +381,7 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
432
381
|
* @returns {Promise<void>}
|
|
433
382
|
*/
|
|
434
383
|
async refreshData() {
|
|
435
|
-
console.log('[WeatherLayerManager] Manual data refresh triggered.');
|
|
384
|
+
//console.log('[WeatherLayerManager] Manual data refresh triggered.');
|
|
436
385
|
// This just calls the internal logic we already built.
|
|
437
386
|
await this._checkForUpdates();
|
|
438
387
|
}
|
|
@@ -480,8 +429,14 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
480
429
|
this.emit('data:updated', { type: 'mrms', variable: currentVariable, newTimestamps: newTimestampsToPreload });
|
|
481
430
|
}
|
|
482
431
|
} else {
|
|
432
|
+
const previousStatus = this.core.modelStatus;
|
|
483
433
|
const modelStatus = await this.core.fetchModelStatus(true);
|
|
484
|
-
|
|
434
|
+
|
|
435
|
+
// Only emit if the status actually changed
|
|
436
|
+
const statusChanged = JSON.stringify(previousStatus) !== JSON.stringify(modelStatus);
|
|
437
|
+
if (statusChanged) {
|
|
438
|
+
this.core._emitStateChange();
|
|
439
|
+
}
|
|
485
440
|
|
|
486
441
|
const latestRun = findLatestModelRun(modelStatus, currentModel);
|
|
487
442
|
if (!latestRun) return;
|
|
@@ -525,6 +480,6 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
525
480
|
// 4. Clear any remaining internal state
|
|
526
481
|
this.currentLoadedTimeKey = null;
|
|
527
482
|
|
|
528
|
-
console.log(`WeatherLayerManager with id "${this.layerId}" has been destroyed.`);
|
|
483
|
+
//console.log(`WeatherLayerManager with id "${this.layerId}" has been destroyed.`);
|
|
529
484
|
}
|
|
530
485
|
}
|