esri-gl 0.9.0-alpha.13 → 0.9.0-alpha.14
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/README.md +15 -2
- package/dist/esri-gl.esm.js +242 -68
- package/dist/esri-gl.esm.js.map +1 -1
- package/dist/esri-gl.js +242 -68
- package/dist/esri-gl.js.map +1 -1
- package/dist/esri-gl.min.js +1 -1
- package/dist/esri-gl.min.js.map +1 -1
- package/dist/index-CdJejJJr.d.ts +1249 -0
- package/dist/index.d.ts +1 -1248
- package/dist/index.js +242 -68
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +242 -68
- package/dist/index.umd.js.map +1 -1
- package/dist/package.json +65 -0
- package/dist/react-map-gl.d.ts +3 -3
- package/dist/react-map-gl.js +188 -47
- package/dist/react-map-gl.js.map +1 -1
- package/dist/react.d.ts +19 -6
- package/dist/react.js +81 -29
- package/dist/react.js.map +1 -1
- package/dist/{useFeatureService-CLnmgBg3.d.ts → useFeatureService-BcsU4_Da.d.ts} +8 -12
- package/dist/{useFeatureService-Dsqu-yjX.js → useFeatureService-C8yzDPdU.js} +43 -26
- package/dist/useFeatureService-C8yzDPdU.js.map +1 -0
- package/package.json +17 -5
- package/dist/useFeatureService-Dsqu-yjX.js.map +0 -1
package/README.md
CHANGED
|
@@ -368,7 +368,7 @@ For the smoothest React experience with declarative layer management:
|
|
|
368
368
|
|
|
369
369
|
```typescript
|
|
370
370
|
import React, { useState } from 'react';
|
|
371
|
-
import { Map } from 'react-map-gl';
|
|
371
|
+
import { Map } from 'react-map-gl/mapbox';
|
|
372
372
|
import {
|
|
373
373
|
EsriDynamicLayer,
|
|
374
374
|
EsriFeatureLayer,
|
|
@@ -485,7 +485,7 @@ import type {
|
|
|
485
485
|
IdentifyResult,
|
|
486
486
|
EsriLayerProps
|
|
487
487
|
} from 'esri-gl';
|
|
488
|
-
import type { MapRef } from 'react-map-gl';
|
|
488
|
+
import type { MapRef } from 'react-map-gl/mapbox';
|
|
489
489
|
|
|
490
490
|
// Fully typed component props
|
|
491
491
|
interface MapComponentProps {
|
|
@@ -653,6 +653,8 @@ All type declarations are available in the `dist/` directory after building.
|
|
|
653
653
|
|
|
654
654
|
## Contributing
|
|
655
655
|
|
|
656
|
+
We welcome contributions! Please follow these steps:
|
|
657
|
+
|
|
656
658
|
1. Fork the repository
|
|
657
659
|
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
658
660
|
3. Make changes and add tests
|
|
@@ -661,6 +663,17 @@ All type declarations are available in the `dist/` directory after building.
|
|
|
661
663
|
6. Push to branch: `git push origin feature/my-feature`
|
|
662
664
|
7. Submit a pull request
|
|
663
665
|
|
|
666
|
+
### Pre-commit Hooks
|
|
667
|
+
|
|
668
|
+
This project uses [Husky](https://typicode.github.io/husky/) to automatically run quality checks before each commit:
|
|
669
|
+
|
|
670
|
+
- **Formatting & Linting**: Automatically formats and lints staged files using Prettier and ESLint
|
|
671
|
+
- **Testing**: Runs the full test suite to ensure no regressions
|
|
672
|
+
|
|
673
|
+
The hooks are automatically installed when you run `npm install`. If you need to skip them (not recommended), you can use `git commit --no-verify`.
|
|
674
|
+
|
|
675
|
+
For more details, see [.husky/README.md](.husky/README.md).
|
|
676
|
+
|
|
664
677
|
## License
|
|
665
678
|
|
|
666
679
|
MIT License - see [LICENSE](LICENSE) file for details.
|
package/dist/esri-gl.esm.js
CHANGED
|
@@ -462,7 +462,11 @@ class DynamicMapService {
|
|
|
462
462
|
this.rasterSrcOptions = rasterSrcOptions;
|
|
463
463
|
this.esriServiceOptions = esriServiceOptions;
|
|
464
464
|
this._createSource();
|
|
465
|
-
if (this.options.getAttributionFromService)
|
|
465
|
+
if (this.options.getAttributionFromService) {
|
|
466
|
+
this.setAttributionFromService().catch(() => {
|
|
467
|
+
// Silently handle attribution fetch errors to prevent unhandled rejections
|
|
468
|
+
});
|
|
469
|
+
}
|
|
466
470
|
}
|
|
467
471
|
get options() {
|
|
468
472
|
return {
|
|
@@ -543,7 +547,10 @@ class DynamicMapService {
|
|
|
543
547
|
};
|
|
544
548
|
}
|
|
545
549
|
_createSource() {
|
|
546
|
-
|
|
550
|
+
// Check if source already exists before adding
|
|
551
|
+
if (!this._map.getSource(this._sourceId)) {
|
|
552
|
+
this._map.addSource(this._sourceId, this._source);
|
|
553
|
+
}
|
|
547
554
|
}
|
|
548
555
|
// This requires hooking into some undocumented methods
|
|
549
556
|
_updateSource() {
|
|
@@ -562,11 +569,21 @@ class DynamicMapService {
|
|
|
562
569
|
const src = this._map.getSource(this._sourceId);
|
|
563
570
|
if (!src) return;
|
|
564
571
|
try {
|
|
565
|
-
src.tiles
|
|
572
|
+
// Ensure src.tiles exists before accessing it
|
|
573
|
+
if (src.tiles && Array.isArray(src.tiles) && this._source.tiles && this._source.tiles.length > 0) {
|
|
574
|
+
src.tiles[0] = this._source.tiles[0];
|
|
575
|
+
}
|
|
566
576
|
src._options = this._source;
|
|
567
577
|
if (src.setTiles) {
|
|
568
578
|
// New MapboxGL >= 2.13.0
|
|
569
|
-
|
|
579
|
+
// setTiles may return a promise - handle rejections to prevent console errors
|
|
580
|
+
const result = src.setTiles(this._source.tiles);
|
|
581
|
+
if (result && typeof result.catch === 'function') {
|
|
582
|
+
result.catch(() => {
|
|
583
|
+
// Silently ignore - setTiles rejections are often abort errors during rapid updates
|
|
584
|
+
// The outer try/catch will handle any synchronous errors
|
|
585
|
+
});
|
|
586
|
+
}
|
|
570
587
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
571
588
|
} else if (this._map.style.sourceCaches) {
|
|
572
589
|
// Old MapboxGL and MaplibreGL
|
|
@@ -582,8 +599,21 @@ class DynamicMapService {
|
|
|
582
599
|
this._map.style.sourceCaches[this._sourceId].update(this._map.transform);
|
|
583
600
|
}
|
|
584
601
|
} catch (error) {
|
|
585
|
-
|
|
586
|
-
|
|
602
|
+
// Comprehensive abort detection - check all possible error shapes
|
|
603
|
+
// MapLibre can throw various forms of AbortError
|
|
604
|
+
const errorName = error?.name;
|
|
605
|
+
const errorMessage = error?.message;
|
|
606
|
+
const errorConstructor = error?.constructor?.name;
|
|
607
|
+
let stringified = '';
|
|
608
|
+
try {
|
|
609
|
+
stringified = String(error);
|
|
610
|
+
} catch {
|
|
611
|
+
// ignore
|
|
612
|
+
}
|
|
613
|
+
// Check every possible way an error could represent AbortError
|
|
614
|
+
const isAbortError = error instanceof DOMException && error.name === 'AbortError' || error instanceof Error && error.name === 'AbortError' || errorName === 'AbortError' || errorConstructor === 'AbortError' || errorMessage?.toLowerCase().includes('abort') || stringified.toLowerCase().includes('abort') || errorMessage?.includes('AbortError') || stringified.includes('AbortError') || stringified === 'Error: AbortError' || error === 'AbortError';
|
|
615
|
+
if (isAbortError) {
|
|
616
|
+
// Silently ignore aborted tile operations - MapLibre will retry
|
|
587
617
|
return;
|
|
588
618
|
}
|
|
589
619
|
// Swallow occasional transient errors that can happen during style reloads
|
|
@@ -1146,7 +1176,54 @@ class DynamicMapService {
|
|
|
1146
1176
|
this._updateSource();
|
|
1147
1177
|
}
|
|
1148
1178
|
remove() {
|
|
1149
|
-
this._map
|
|
1179
|
+
const map = this._map;
|
|
1180
|
+
if (!map || typeof map.removeSource !== 'function') {
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
try {
|
|
1184
|
+
const mapWithStyle = map;
|
|
1185
|
+
const mapLayerApi = map;
|
|
1186
|
+
const mapSourceApi = map;
|
|
1187
|
+
if (typeof mapWithStyle.getStyle === 'function') {
|
|
1188
|
+
const style = mapWithStyle.getStyle();
|
|
1189
|
+
const layers = style?.layers || [];
|
|
1190
|
+
layers.forEach(layer => {
|
|
1191
|
+
if (layer.source !== this._sourceId) return;
|
|
1192
|
+
if (typeof mapLayerApi.getLayer !== 'function' || typeof mapLayerApi.removeLayer !== 'function') {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
let hasLayer = false;
|
|
1196
|
+
try {
|
|
1197
|
+
hasLayer = Boolean(mapLayerApi.getLayer(layer.id));
|
|
1198
|
+
} catch {
|
|
1199
|
+
hasLayer = false;
|
|
1200
|
+
}
|
|
1201
|
+
if (!hasLayer) return;
|
|
1202
|
+
try {
|
|
1203
|
+
mapLayerApi.removeLayer(layer.id);
|
|
1204
|
+
} catch (error) {
|
|
1205
|
+
console.warn(`Failed to remove layer ${layer.id} for source ${this._sourceId}:`, error);
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
if (typeof mapSourceApi.getSource === 'function') {
|
|
1210
|
+
let hasSource = false;
|
|
1211
|
+
try {
|
|
1212
|
+
hasSource = Boolean(mapSourceApi.getSource(this._sourceId));
|
|
1213
|
+
} catch {
|
|
1214
|
+
hasSource = false;
|
|
1215
|
+
}
|
|
1216
|
+
if (hasSource) {
|
|
1217
|
+
try {
|
|
1218
|
+
map.removeSource(this._sourceId);
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
console.warn(`Failed to remove source ${this._sourceId}:`, error);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
console.warn(`Failed to remove source ${this._sourceId}:`, error);
|
|
1226
|
+
}
|
|
1150
1227
|
}
|
|
1151
1228
|
}
|
|
1152
1229
|
|
|
@@ -1206,7 +1283,10 @@ class TiledMapService {
|
|
|
1206
1283
|
};
|
|
1207
1284
|
}
|
|
1208
1285
|
_createSource() {
|
|
1209
|
-
|
|
1286
|
+
// Check if source already exists before adding
|
|
1287
|
+
if (!this._map.getSource(this._sourceId)) {
|
|
1288
|
+
this._map.addSource(this._sourceId, this._source);
|
|
1289
|
+
}
|
|
1210
1290
|
}
|
|
1211
1291
|
setAttributionFromService() {
|
|
1212
1292
|
if (this._serviceMetadata) {
|
|
@@ -1233,7 +1313,39 @@ class TiledMapService {
|
|
|
1233
1313
|
this._map.getSource(this._sourceId);
|
|
1234
1314
|
}
|
|
1235
1315
|
remove() {
|
|
1236
|
-
|
|
1316
|
+
// Guard against disposed or invalid map
|
|
1317
|
+
if (!this._map || typeof this._map.removeSource !== 'function') {
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
try {
|
|
1321
|
+
// First, remove any layers that are using this source
|
|
1322
|
+
const mapWithStyle = this._map;
|
|
1323
|
+
if (mapWithStyle.getStyle && typeof mapWithStyle.getLayer === 'function') {
|
|
1324
|
+
const style = mapWithStyle.getStyle();
|
|
1325
|
+
const layers = style?.layers || [];
|
|
1326
|
+
const getLayer = mapWithStyle.getLayer;
|
|
1327
|
+
layers.forEach(layer => {
|
|
1328
|
+
if (layer.source === this._sourceId) {
|
|
1329
|
+
try {
|
|
1330
|
+
if (getLayer(layer.id)) {
|
|
1331
|
+
this._map.removeLayer(layer.id);
|
|
1332
|
+
}
|
|
1333
|
+
} catch {
|
|
1334
|
+
// Layer may already be removed
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
// Then check if source exists before trying to remove it
|
|
1340
|
+
if (typeof this._map.getSource === 'function') {
|
|
1341
|
+
const source = this._map.getSource(this._sourceId);
|
|
1342
|
+
if (source) {
|
|
1343
|
+
this._map.removeSource(this._sourceId);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
console.warn(`Failed to remove source ${this._sourceId}:`, error);
|
|
1348
|
+
}
|
|
1237
1349
|
}
|
|
1238
1350
|
}
|
|
1239
1351
|
|
|
@@ -1294,7 +1406,11 @@ class ImageService {
|
|
|
1294
1406
|
this.rasterSrcOptions = rasterSrcOptions;
|
|
1295
1407
|
this.esriServiceOptions = esriServiceOptions;
|
|
1296
1408
|
this._createSource();
|
|
1297
|
-
if (this.options.getAttributionFromService)
|
|
1409
|
+
if (this.options.getAttributionFromService) {
|
|
1410
|
+
this.setAttributionFromService().catch(() => {
|
|
1411
|
+
// Silently handle attribution fetch errors to prevent unhandled rejections
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1298
1414
|
}
|
|
1299
1415
|
get options() {
|
|
1300
1416
|
return {
|
|
@@ -1332,11 +1448,18 @@ class ImageService {
|
|
|
1332
1448
|
};
|
|
1333
1449
|
}
|
|
1334
1450
|
_createSource() {
|
|
1335
|
-
|
|
1451
|
+
// Check if source already exists before adding
|
|
1452
|
+
if (!this._map.getSource(this._sourceId)) {
|
|
1453
|
+
this._map.addSource(this._sourceId, this._source);
|
|
1454
|
+
}
|
|
1336
1455
|
}
|
|
1337
1456
|
// This requires hooking into some undocumented methods
|
|
1338
1457
|
_updateSource() {
|
|
1339
1458
|
const src = this._map.getSource(this._sourceId);
|
|
1459
|
+
if (!src) {
|
|
1460
|
+
// Source not yet added to map, nothing to update
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1340
1463
|
src.tiles[0] = this._source.tiles[0];
|
|
1341
1464
|
src._options = this._source;
|
|
1342
1465
|
if (src.setTiles) {
|
|
@@ -1411,7 +1534,27 @@ class ImageService {
|
|
|
1411
1534
|
this._updateSource();
|
|
1412
1535
|
}
|
|
1413
1536
|
remove() {
|
|
1414
|
-
this._map.removeSource
|
|
1537
|
+
if (this._map && typeof this._map.removeSource === 'function') {
|
|
1538
|
+
try {
|
|
1539
|
+
// First, remove any layers that are using this source
|
|
1540
|
+
const mapWithStyle = this._map;
|
|
1541
|
+
if (mapWithStyle.getStyle) {
|
|
1542
|
+
const style = mapWithStyle.getStyle();
|
|
1543
|
+
const layers = style?.layers || [];
|
|
1544
|
+
layers.forEach(layer => {
|
|
1545
|
+
if (layer.source === this._sourceId && this._map.getLayer(layer.id)) {
|
|
1546
|
+
this._map.removeLayer(layer.id);
|
|
1547
|
+
}
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
// Then check if source exists before trying to remove it
|
|
1551
|
+
if (this._map.getSource && this._map.getSource(this._sourceId)) {
|
|
1552
|
+
this._map.removeSource(this._sourceId);
|
|
1553
|
+
}
|
|
1554
|
+
} catch (error) {
|
|
1555
|
+
console.warn(`Failed to remove source ${this._sourceId}:`, error);
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1415
1558
|
}
|
|
1416
1559
|
}
|
|
1417
1560
|
|
|
@@ -1659,7 +1802,10 @@ class VectorTileService {
|
|
|
1659
1802
|
};
|
|
1660
1803
|
}
|
|
1661
1804
|
_createSource() {
|
|
1662
|
-
|
|
1805
|
+
// Check if source already exists before adding
|
|
1806
|
+
if (!this._map.getSource(this._sourceId)) {
|
|
1807
|
+
this._map.addSource(this._sourceId, this._source);
|
|
1808
|
+
}
|
|
1663
1809
|
}
|
|
1664
1810
|
_mapToLocalSource(style) {
|
|
1665
1811
|
return {
|
|
@@ -1720,7 +1866,54 @@ class VectorTileService {
|
|
|
1720
1866
|
// Vector tile services don't need dynamic updates like dynamic services
|
|
1721
1867
|
}
|
|
1722
1868
|
remove() {
|
|
1723
|
-
this._map
|
|
1869
|
+
const map = this._map;
|
|
1870
|
+
if (!map || typeof map.removeSource !== 'function') {
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
try {
|
|
1874
|
+
const mapWithStyle = map;
|
|
1875
|
+
const mapLayerApi = map;
|
|
1876
|
+
const mapSourceApi = map;
|
|
1877
|
+
if (typeof mapWithStyle.getStyle === 'function') {
|
|
1878
|
+
const style = mapWithStyle.getStyle();
|
|
1879
|
+
const layers = style?.layers || [];
|
|
1880
|
+
layers.forEach(layer => {
|
|
1881
|
+
if (layer.source !== this._sourceId) return;
|
|
1882
|
+
if (typeof mapLayerApi.getLayer !== 'function' || typeof mapLayerApi.removeLayer !== 'function') {
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
let hasLayer = false;
|
|
1886
|
+
try {
|
|
1887
|
+
hasLayer = Boolean(mapLayerApi.getLayer(layer.id));
|
|
1888
|
+
} catch {
|
|
1889
|
+
hasLayer = false;
|
|
1890
|
+
}
|
|
1891
|
+
if (!hasLayer) return;
|
|
1892
|
+
try {
|
|
1893
|
+
mapLayerApi.removeLayer(layer.id);
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
console.warn(`Failed to remove layer ${layer.id} for source ${this._sourceId}:`, error);
|
|
1896
|
+
}
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
if (typeof mapSourceApi.getSource === 'function') {
|
|
1900
|
+
let hasSource = false;
|
|
1901
|
+
try {
|
|
1902
|
+
hasSource = Boolean(mapSourceApi.getSource(this._sourceId));
|
|
1903
|
+
} catch {
|
|
1904
|
+
hasSource = false;
|
|
1905
|
+
}
|
|
1906
|
+
if (hasSource) {
|
|
1907
|
+
try {
|
|
1908
|
+
map.removeSource(this._sourceId);
|
|
1909
|
+
} catch (error) {
|
|
1910
|
+
console.warn(`Failed to remove source ${this._sourceId}:`, error);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
} catch (error) {
|
|
1915
|
+
console.warn(`Failed to remove source ${this._sourceId}:`, error);
|
|
1916
|
+
}
|
|
1724
1917
|
}
|
|
1725
1918
|
}
|
|
1726
1919
|
|
|
@@ -1803,46 +1996,35 @@ class FeatureService {
|
|
|
1803
1996
|
this._createSource();
|
|
1804
1997
|
}
|
|
1805
1998
|
async _createSource() {
|
|
1999
|
+
if (!this._map) return;
|
|
1806
2000
|
try {
|
|
1807
2001
|
// Get service metadata
|
|
1808
2002
|
this._serviceMetadata = await getServiceDetails(this.esriServiceOptions.url, this.esriServiceOptions.fetchOptions);
|
|
1809
2003
|
// Check if vector tiles should be used (default behavior)
|
|
1810
2004
|
// Note: Most FeatureServers don't support vector tiles, so we'll detect and fallback
|
|
1811
|
-
const isTestEnvironment = typeof process !== 'undefined' && process.env?.NODE_ENV === 'test';
|
|
1812
|
-
if (!isTestEnvironment) {
|
|
1813
|
-
console.log('FeatureService: useVectorTiles setting:', this.esriServiceOptions.useVectorTiles);
|
|
1814
|
-
}
|
|
1815
2005
|
const vectorTileSupport = await this._checkVectorTileSupport();
|
|
1816
|
-
if (!isTestEnvironment) {
|
|
1817
|
-
console.log('FeatureService: Vector tile support detected:', vectorTileSupport);
|
|
1818
|
-
}
|
|
1819
2006
|
const useVectorTiles = this.esriServiceOptions.useVectorTiles !== false && vectorTileSupport;
|
|
1820
|
-
if (!isTestEnvironment) {
|
|
1821
|
-
console.log('FeatureService: Final decision - using vector tiles:', useVectorTiles);
|
|
1822
|
-
}
|
|
1823
2007
|
if (useVectorTiles) {
|
|
1824
2008
|
// Create vector tile source
|
|
1825
2009
|
const tileUrl = this._buildTileUrl();
|
|
1826
|
-
if
|
|
1827
|
-
|
|
2010
|
+
// Add vector source to map if it doesn't already exist
|
|
2011
|
+
if (!this._map.getSource(this._sourceId)) {
|
|
2012
|
+
this._map.addSource(this._sourceId, {
|
|
2013
|
+
type: 'vector',
|
|
2014
|
+
tiles: [tileUrl],
|
|
2015
|
+
maxzoom: 24,
|
|
2016
|
+
...this.vectorSrcOptions
|
|
2017
|
+
});
|
|
1828
2018
|
}
|
|
1829
|
-
// Add vector source to map
|
|
1830
|
-
this._map.addSource(this._sourceId, {
|
|
1831
|
-
type: 'vector',
|
|
1832
|
-
tiles: [tileUrl],
|
|
1833
|
-
maxzoom: 24,
|
|
1834
|
-
...this.vectorSrcOptions
|
|
1835
|
-
});
|
|
1836
2019
|
} else {
|
|
1837
2020
|
// Fallback to GeoJSON (most common for FeatureServers)
|
|
1838
2021
|
const queryUrl = this._buildQueryUrl();
|
|
1839
|
-
if (!
|
|
1840
|
-
|
|
2022
|
+
if (!this._map.getSource(this._sourceId)) {
|
|
2023
|
+
this._map.addSource(this._sourceId, {
|
|
2024
|
+
type: 'geojson',
|
|
2025
|
+
data: queryUrl
|
|
2026
|
+
});
|
|
1841
2027
|
}
|
|
1842
|
-
this._map.addSource(this._sourceId, {
|
|
1843
|
-
type: 'geojson',
|
|
1844
|
-
data: queryUrl
|
|
1845
|
-
});
|
|
1846
2028
|
}
|
|
1847
2029
|
// Update attribution after source is added if available in service metadata
|
|
1848
2030
|
if (this._serviceMetadata?.copyrightText) {
|
|
@@ -1867,42 +2049,20 @@ class FeatureService {
|
|
|
1867
2049
|
const vectorTileUrl = this.esriServiceOptions.url.replace('/FeatureServer/', '/VectorTileServer/');
|
|
1868
2050
|
// Only check if the URL actually changed (meaning it was a FeatureServer URL)
|
|
1869
2051
|
if (vectorTileUrl === this.esriServiceOptions.url) {
|
|
1870
|
-
const isTestEnvironment = typeof process !== 'undefined' && process.env?.NODE_ENV === 'test';
|
|
1871
|
-
if (!isTestEnvironment) {
|
|
1872
|
-
console.log('FeatureService: Not a FeatureServer URL, falling back to GeoJSON');
|
|
1873
|
-
}
|
|
1874
2052
|
return false;
|
|
1875
2053
|
}
|
|
1876
|
-
const isTestEnvironment = typeof process !== 'undefined' && process.env?.NODE_ENV === 'test';
|
|
1877
|
-
if (!isTestEnvironment) {
|
|
1878
|
-
console.log('FeatureService: Checking vector tile support at:', vectorTileUrl);
|
|
1879
|
-
}
|
|
1880
2054
|
const response = await fetch(vectorTileUrl + '?f=json', this.esriServiceOptions.fetchOptions);
|
|
1881
2055
|
if (response.ok) {
|
|
1882
2056
|
const data = await response.json();
|
|
1883
2057
|
if (data && !data.error) {
|
|
1884
|
-
if (!isTestEnvironment) {
|
|
1885
|
-
console.log('FeatureService: Vector tile endpoint found and working:', vectorTileUrl);
|
|
1886
|
-
console.log('FeatureService: Vector tile service data:', data);
|
|
1887
|
-
}
|
|
1888
2058
|
return true;
|
|
1889
2059
|
} else {
|
|
1890
|
-
if (!isTestEnvironment) {
|
|
1891
|
-
console.log('FeatureService: Vector tile endpoint returned error:', data?.error);
|
|
1892
|
-
}
|
|
1893
2060
|
return false;
|
|
1894
2061
|
}
|
|
1895
2062
|
} else {
|
|
1896
|
-
if (!isTestEnvironment) {
|
|
1897
|
-
console.log('FeatureService: Vector tile endpoint returned HTTP', response.status);
|
|
1898
|
-
}
|
|
1899
2063
|
return false;
|
|
1900
2064
|
}
|
|
1901
|
-
} catch
|
|
1902
|
-
const isTestEnvironment = typeof process !== 'undefined' && process.env?.NODE_ENV === 'test';
|
|
1903
|
-
if (!isTestEnvironment) {
|
|
1904
|
-
console.log('FeatureService: Vector tile check failed, falling back to GeoJSON:', error);
|
|
1905
|
-
}
|
|
2065
|
+
} catch {
|
|
1906
2066
|
return false;
|
|
1907
2067
|
}
|
|
1908
2068
|
}
|
|
@@ -2047,10 +2207,6 @@ class FeatureService {
|
|
|
2047
2207
|
const source = this._map.getSource(this._sourceId);
|
|
2048
2208
|
if (source && 'setData' in source && typeof source.setData === 'function') {
|
|
2049
2209
|
const newQueryUrl = this._buildQueryUrl();
|
|
2050
|
-
const isTestEnvironment = typeof process !== 'undefined' && process.env?.NODE_ENV === 'test';
|
|
2051
|
-
if (!isTestEnvironment) {
|
|
2052
|
-
console.log('Updating FeatureService data with new bounding box:', newQueryUrl);
|
|
2053
|
-
}
|
|
2054
2210
|
// @ts-ignore - GeoJSON source setData method not in generic Source type
|
|
2055
2211
|
source.setData(newQueryUrl);
|
|
2056
2212
|
}
|
|
@@ -2131,8 +2287,26 @@ class FeatureService {
|
|
|
2131
2287
|
// Note: maxRecordCount is a server capability; not settable via query params
|
|
2132
2288
|
remove() {
|
|
2133
2289
|
this._removeBoundingBoxUpdates();
|
|
2134
|
-
if (this._map
|
|
2135
|
-
|
|
2290
|
+
if (this._map && typeof this._map.removeSource === 'function') {
|
|
2291
|
+
try {
|
|
2292
|
+
// First, remove any layers that are using this source
|
|
2293
|
+
const mapWithStyle = this._map;
|
|
2294
|
+
if (mapWithStyle.getStyle) {
|
|
2295
|
+
const style = mapWithStyle.getStyle();
|
|
2296
|
+
const layers = style?.layers || [];
|
|
2297
|
+
layers.forEach(layer => {
|
|
2298
|
+
if (layer.source === this._sourceId && this._map.getLayer && this._map.getLayer(layer.id)) {
|
|
2299
|
+
this._map.removeLayer(layer.id);
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
// Then check if source exists before trying to remove it
|
|
2304
|
+
if (this._map.getSource && this._map.getSource(this._sourceId)) {
|
|
2305
|
+
this._map.removeSource(this._sourceId);
|
|
2306
|
+
}
|
|
2307
|
+
} catch (error) {
|
|
2308
|
+
console.warn(`Failed to remove source ${this._sourceId}:`, error);
|
|
2309
|
+
}
|
|
2136
2310
|
}
|
|
2137
2311
|
}
|
|
2138
2312
|
async queryFeatures(options) {
|