@aguacerowx/mapsgl 0.0.57 → 0.0.58

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.
@@ -1,148 +1,148 @@
1
- /**
2
- * GeoJSON markers for all NEXRAD sites (picker mode). Aligned with aguacero-frontend NexradSitesLayer (simplified).
3
- */
4
- const SOURCE_ID = 'aguacero-nexrad-sites-src';
5
- const CIRCLE_LAYER_ID = 'aguacero-nexrad-sites-circles';
6
-
7
- export class NexradSitesOverlay {
8
- constructor(map, options = {}) {
9
- this.map = map;
10
- /** Same path as aguacero-frontend: serve `public/data/nexrad.json` (e.g. Vite → `/data/nexrad.json`). */
11
- this.sitesUrl = options.nexradSitesUrl || '/data/nexrad.json';
12
- this._onClick = null;
13
- /** Coalesces overlapping `show()` calls (e.g. NEXRAD timestamp slider firing many state updates). */
14
- this._showPromise = null;
15
- this._destroyed = false;
16
- }
17
-
18
- _layersPresent() {
19
- try {
20
- return Boolean(this.map.getSource(SOURCE_ID) && this.map.getLayer(CIRCLE_LAYER_ID));
21
- } catch {
22
- return false;
23
- }
24
- }
25
-
26
- async show() {
27
- if (this._layersPresent()) {
28
- return;
29
- }
30
- if (this._showPromise) {
31
- return this._showPromise;
32
- }
33
-
34
- this._showPromise = this._loadAndMountSites();
35
- try {
36
- await this._showPromise;
37
- } finally {
38
- this._showPromise = null;
39
- }
40
- }
41
-
42
- async _loadAndMountSites() {
43
- if (this._layersPresent()) {
44
- return;
45
- }
46
- await this.hide();
47
- let res;
48
- try {
49
- res = await fetch(this.sitesUrl);
50
- } catch (e) {
51
- console.warn('[NexradSitesOverlay] Failed to load site list:', e);
52
- return;
53
- }
54
- if (!res.ok) {
55
- console.warn('[NexradSitesOverlay] HTTP', res.status, this.sitesUrl);
56
- return;
57
- }
58
- if (this._destroyed) {
59
- return;
60
- }
61
- const payload = await res.json();
62
- const raw = Array.isArray(payload)
63
- ? payload
64
- : payload?.features
65
- ? payload.features
66
- : payload?.sites
67
- ? payload.sites
68
- : [];
69
- const features = [];
70
- for (const item of raw) {
71
- if (!item) continue;
72
- const coords = item.geometry?.coordinates
73
- ? item.geometry.coordinates
74
- : [item.lon ?? item.lng ?? item.longitude, item.lat ?? item.latitude];
75
- const lon = Number(coords[0]);
76
- const lat = Number(coords[1]);
77
- const id = String(item.id ?? item.properties?.id ?? item.station ?? '').toUpperCase();
78
- if (!id || !Number.isFinite(lat) || !Number.isFinite(lon)) continue;
79
- features.push({
80
- type: 'Feature',
81
- geometry: { type: 'Point', coordinates: [lon, lat] },
82
- properties: { name: id },
83
- });
84
- }
85
- if (this._destroyed) {
86
- return;
87
- }
88
- this.map.addSource(SOURCE_ID, {
89
- type: 'geojson',
90
- data: { type: 'FeatureCollection', features },
91
- });
92
- this.map.addLayer({
93
- id: CIRCLE_LAYER_ID,
94
- type: 'circle',
95
- source: SOURCE_ID,
96
- paint: {
97
- 'circle-radius': 5,
98
- 'circle-color': '#3b82f6',
99
- 'circle-stroke-width': 1,
100
- 'circle-stroke-color': '#ffffff',
101
- },
102
- });
103
- }
104
-
105
- hide() {
106
- try {
107
- if (this.map.getLayer(CIRCLE_LAYER_ID)) this.map.removeLayer(CIRCLE_LAYER_ID);
108
- if (this.map.getSource(SOURCE_ID)) this.map.removeSource(SOURCE_ID);
109
- } catch {
110
- /* ignore */
111
- }
112
- }
113
-
114
- /**
115
- * @param {(siteId: string) => void} handler
116
- */
117
- bindClick(handler) {
118
- this.unbindClick();
119
- this._onClick = (e) => {
120
- const f = e.features?.[0];
121
- const id = f?.properties?.name;
122
- if (id) handler(String(id));
123
- };
124
- this.map.on('click', CIRCLE_LAYER_ID, this._onClick);
125
- this.map.on('mouseenter', CIRCLE_LAYER_ID, () => {
126
- this.map.getCanvas().style.cursor = 'pointer';
127
- });
128
- this.map.on('mouseleave', CIRCLE_LAYER_ID, () => {
129
- this.map.getCanvas().style.cursor = '';
130
- });
131
- }
132
-
133
- unbindClick() {
134
- if (!this._onClick) return;
135
- try {
136
- this.map.off('click', CIRCLE_LAYER_ID, this._onClick);
137
- } catch {
138
- /* ignore */
139
- }
140
- this._onClick = null;
141
- }
142
-
143
- destroy() {
144
- this._destroyed = true;
145
- this.unbindClick();
146
- this.hide();
147
- }
148
- }
1
+ /**
2
+ * GeoJSON markers for all NEXRAD sites (picker mode). Aligned with aguacero-frontend NexradSitesLayer (simplified).
3
+ */
4
+ const SOURCE_ID = 'aguacero-nexrad-sites-src';
5
+ const CIRCLE_LAYER_ID = 'aguacero-nexrad-sites-circles';
6
+
7
+ export class NexradSitesOverlay {
8
+ constructor(map, options = {}) {
9
+ this.map = map;
10
+ /** Same path as aguacero-frontend: serve `public/data/nexrad.json` (e.g. Vite → `/data/nexrad.json`). */
11
+ this.sitesUrl = options.nexradSitesUrl || '/data/nexrad.json';
12
+ this._onClick = null;
13
+ /** Coalesces overlapping `show()` calls (e.g. NEXRAD timestamp slider firing many state updates). */
14
+ this._showPromise = null;
15
+ this._destroyed = false;
16
+ }
17
+
18
+ _layersPresent() {
19
+ try {
20
+ return Boolean(this.map.getSource(SOURCE_ID) && this.map.getLayer(CIRCLE_LAYER_ID));
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ async show() {
27
+ if (this._layersPresent()) {
28
+ return;
29
+ }
30
+ if (this._showPromise) {
31
+ return this._showPromise;
32
+ }
33
+
34
+ this._showPromise = this._loadAndMountSites();
35
+ try {
36
+ await this._showPromise;
37
+ } finally {
38
+ this._showPromise = null;
39
+ }
40
+ }
41
+
42
+ async _loadAndMountSites() {
43
+ if (this._layersPresent()) {
44
+ return;
45
+ }
46
+ await this.hide();
47
+ let res;
48
+ try {
49
+ res = await fetch(this.sitesUrl);
50
+ } catch (e) {
51
+ console.warn('[NexradSitesOverlay] Failed to load site list:', e);
52
+ return;
53
+ }
54
+ if (!res.ok) {
55
+ console.warn('[NexradSitesOverlay] HTTP', res.status, this.sitesUrl);
56
+ return;
57
+ }
58
+ if (this._destroyed) {
59
+ return;
60
+ }
61
+ const payload = await res.json();
62
+ const raw = Array.isArray(payload)
63
+ ? payload
64
+ : payload?.features
65
+ ? payload.features
66
+ : payload?.sites
67
+ ? payload.sites
68
+ : [];
69
+ const features = [];
70
+ for (const item of raw) {
71
+ if (!item) continue;
72
+ const coords = item.geometry?.coordinates
73
+ ? item.geometry.coordinates
74
+ : [item.lon ?? item.lng ?? item.longitude, item.lat ?? item.latitude];
75
+ const lon = Number(coords[0]);
76
+ const lat = Number(coords[1]);
77
+ const id = String(item.id ?? item.properties?.id ?? item.station ?? '').toUpperCase();
78
+ if (!id || !Number.isFinite(lat) || !Number.isFinite(lon)) continue;
79
+ features.push({
80
+ type: 'Feature',
81
+ geometry: { type: 'Point', coordinates: [lon, lat] },
82
+ properties: { name: id },
83
+ });
84
+ }
85
+ if (this._destroyed) {
86
+ return;
87
+ }
88
+ this.map.addSource(SOURCE_ID, {
89
+ type: 'geojson',
90
+ data: { type: 'FeatureCollection', features },
91
+ });
92
+ this.map.addLayer({
93
+ id: CIRCLE_LAYER_ID,
94
+ type: 'circle',
95
+ source: SOURCE_ID,
96
+ paint: {
97
+ 'circle-radius': 5,
98
+ 'circle-color': '#3b82f6',
99
+ 'circle-stroke-width': 1,
100
+ 'circle-stroke-color': '#ffffff',
101
+ },
102
+ });
103
+ }
104
+
105
+ hide() {
106
+ try {
107
+ if (this.map.getLayer(CIRCLE_LAYER_ID)) this.map.removeLayer(CIRCLE_LAYER_ID);
108
+ if (this.map.getSource(SOURCE_ID)) this.map.removeSource(SOURCE_ID);
109
+ } catch {
110
+ /* ignore */
111
+ }
112
+ }
113
+
114
+ /**
115
+ * @param {(siteId: string) => void} handler
116
+ */
117
+ bindClick(handler) {
118
+ this.unbindClick();
119
+ this._onClick = (e) => {
120
+ const f = e.features?.[0];
121
+ const id = f?.properties?.name;
122
+ if (id) handler(String(id));
123
+ };
124
+ this.map.on('click', CIRCLE_LAYER_ID, this._onClick);
125
+ this.map.on('mouseenter', CIRCLE_LAYER_ID, () => {
126
+ this.map.getCanvas().style.cursor = 'pointer';
127
+ });
128
+ this.map.on('mouseleave', CIRCLE_LAYER_ID, () => {
129
+ this.map.getCanvas().style.cursor = '';
130
+ });
131
+ }
132
+
133
+ unbindClick() {
134
+ if (!this._onClick) return;
135
+ try {
136
+ this.map.off('click', CIRCLE_LAYER_ID, this._onClick);
137
+ } catch {
138
+ /* ignore */
139
+ }
140
+ this._onClick = null;
141
+ }
142
+
143
+ destroy() {
144
+ this._destroyed = true;
145
+ this.unbindClick();
146
+ this.hide();
147
+ }
148
+ }
@@ -8,6 +8,7 @@ import {
8
8
  objectKeyToUrl,
9
9
  setNexradArchiveApiKey,
10
10
  setNexradArchiveBundleId,
11
+ setNexradArchiveSiteOrigin,
11
12
  setNexradSitesFetchAuth,
12
13
  } from './nexrad/radarArchiveCore.bundled.js';
13
14
  import { MapboxRadarLayer } from './nexrad/MapboxRadarLayer.bundled.js';
@@ -275,6 +276,7 @@ export class NexradWeatherController {
275
276
 
276
277
  setNexradArchiveApiKey(this.core.apiKey || '');
277
278
  setNexradArchiveBundleId(this.core.bundleId || '');
279
+ setNexradArchiveSiteOrigin(this.core.gridRequestSiteOrigin || '');
278
280
  setNexradSitesFetchAuth(this.core.apiKey || '', this.core.bundleId || '');
279
281
 
280
282
  const times = [...(state.availableNexradTimestamps || [])]
@@ -362,6 +364,7 @@ export class NexradWeatherController {
362
364
 
363
365
  setNexradArchiveApiKey(this.core.apiKey || '');
364
366
  setNexradArchiveBundleId(this.core.bundleId || '');
367
+ setNexradArchiveSiteOrigin(this.core.gridRequestSiteOrigin || '');
365
368
  setNexradSitesFetchAuth(this.core.apiKey || '', this.core.bundleId || '');
366
369
 
367
370
  const unix = Number(state.nexradTimestamp);