esri-gl 0.9.0-alpha.11 → 0.9.0-alpha.7

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 CHANGED
@@ -2,19 +2,10 @@
2
2
 
3
3
  A TypeScript library that bridges Esri ArcGIS REST services with MapLibre GL JS and Mapbox GL JS. It replicates Esri Leaflet's architecture patterns while being compatible with modern WebGL mapping libraries.
4
4
 
5
- > **🚧 Development Notice**
6
- >
7
- > This project is currently under active development. APIs may change between releases and some features may not be fully stable. Please use with caution in production environments and check the [changelog](CHANGES.md) for breaking changes between versions.
8
-
9
5
  [![npm version](https://badge.fury.io/js/esri-gl.svg)](https://badge.fury.io/js/esri-gl)
10
6
  [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
11
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
12
8
 
13
- ## 🔗 Links
14
-
15
- - **📚 [Documentation](https://esri-gl.netlify.app/)** - Complete API reference and guides
16
- - **🎮 [Live Demos](https://esri-gl-demo.netlify.app/)** - Interactive examples and code samples
17
-
18
9
  **Note**: This library is compatible with both **MapLibre GL JS** and **Mapbox GL JS**.
19
10
 
20
11
  ## Features
@@ -428,13 +428,6 @@ class DynamicMapService {
428
428
  writable: true,
429
429
  value: void 0
430
430
  });
431
- // Transaction-like updates
432
- Object.defineProperty(this, "_pendingUpdates", {
433
- enumerable: true,
434
- configurable: true,
435
- writable: true,
436
- value: null
437
- });
438
431
  if (!esriServiceOptions.url) {
439
432
  throw new Error('A url must be supplied as part of the esriServiceOptions object.');
440
433
  }
@@ -444,7 +437,6 @@ class DynamicMapService {
444
437
  this._defaultEsriOptions = {
445
438
  layers: false,
446
439
  layerDefs: false,
447
- dynamicLayers: false,
448
440
  format: 'png24',
449
441
  dpi: 96,
450
442
  transparent: true,
@@ -486,31 +478,6 @@ class DynamicMapService {
486
478
  to = to.valueOf();
487
479
  return `${from},${to}`;
488
480
  }
489
- // ArcGIS Dynamic Layer styling parameter (JSON string)
490
- get _dynamicLayers() {
491
- const dl = this.options.dynamicLayers;
492
- if (!dl)
493
- return false;
494
- try {
495
- const normalized = dl.map(l => {
496
- const { visible, ...rest } = l;
497
- const withSource = {
498
- ...rest,
499
- // ensure required source exists
500
- source: l.source ?? { type: 'mapLayer', mapLayerId: l.id },
501
- };
502
- // Convert client-friendly 'visible' to ArcGIS 'visibility'
503
- if (typeof visible === 'boolean') {
504
- withSource.visibility = visible;
505
- }
506
- return withSource;
507
- });
508
- return JSON.stringify(normalized);
509
- }
510
- catch {
511
- return false;
512
- }
513
- }
514
481
  get _source() {
515
482
  const tileSize = this.rasterSrcOptions?.tileSize ?? 256;
516
483
  // These are the bare minimum parameters
@@ -528,8 +495,6 @@ class DynamicMapService {
528
495
  params.append('time', this._time);
529
496
  if (this._layerDefs)
530
497
  params.append('layerDefs', this._layerDefs);
531
- if (this._dynamicLayers)
532
- params.append('dynamicLayers', this._dynamicLayers);
533
498
  return {
534
499
  type: 'raster',
535
500
  tiles: [`${this.options.url}/export?bbox={bbox-epsg-3857}&${params.toString()}`],
@@ -542,27 +507,20 @@ class DynamicMapService {
542
507
  }
543
508
  // This requires hooking into some undocumented methods
544
509
  _updateSource() {
545
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
546
510
  const src = this._map.getSource(this._sourceId);
547
511
  src.tiles[0] = this._source.tiles[0];
548
512
  src._options = this._source;
549
513
  if (src.setTiles) {
550
514
  // New MapboxGL >= 2.13.0
551
515
  src.setTiles(this._source.tiles);
552
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
553
516
  }
554
517
  else if (this._map.style.sourceCaches) {
555
518
  // Old MapboxGL and MaplibreGL
556
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
557
519
  this._map.style.sourceCaches[this._sourceId].clearTiles();
558
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
559
520
  this._map.style.sourceCaches[this._sourceId].update(this._map.transform);
560
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
561
521
  }
562
522
  else if (this._map.style._otherSourceCaches) {
563
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
564
523
  this._map.style.sourceCaches[this._sourceId].clearTiles();
565
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
566
524
  this._map.style.sourceCaches[this._sourceId].update(this._map.transform);
567
525
  }
568
526
  }
@@ -570,174 +528,6 @@ class DynamicMapService {
570
528
  this.esriServiceOptions.layerDefs = obj;
571
529
  this._updateSource();
572
530
  }
573
- /**
574
- * Replace the entire dynamicLayers array. Server applies these drawing rules.
575
- * Note: dynamicLayers overrides default drawing for listed sublayers.
576
- */
577
- setDynamicLayers(layers) {
578
- this.esriServiceOptions.dynamicLayers = layers || false;
579
- this._updateSource();
580
- }
581
- /** Helper to ensure all visible layers are included when using dynamicLayers */
582
- _ensureAllVisibleLayers(dynamicLayers) {
583
- const visibleLayerIds = this._getVisibleLayerIds();
584
- const existingIds = new Set(dynamicLayers.map(dl => dl.id));
585
- // Add entries for visible layers that aren't already in dynamicLayers
586
- const additional = visibleLayerIds
587
- .filter(id => !existingIds.has(id))
588
- .map(id => ({ id, visible: true }));
589
- return [...dynamicLayers, ...additional];
590
- }
591
- /** Get the list of currently visible layer IDs */
592
- _getVisibleLayerIds() {
593
- const lyrs = this.options.layers;
594
- if (!lyrs)
595
- return [];
596
- if (!Array.isArray(lyrs))
597
- return [lyrs];
598
- return lyrs;
599
- }
600
- /** Merge/update a sublayer's drawingInfo with provided fields. */
601
- setLayerDrawingInfo(layerId, drawingInfo) {
602
- const current = this.esriServiceOptions.dynamicLayers || [];
603
- const next = Array.isArray(current) ? [...current] : [];
604
- const idx = next.findIndex(l => l.id === layerId);
605
- if (idx >= 0) {
606
- next[idx] = { ...next[idx], drawingInfo: { ...next[idx].drawingInfo, ...drawingInfo } };
607
- }
608
- else {
609
- next.push({ id: layerId, drawingInfo });
610
- }
611
- // Ensure all visible layers are included
612
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(next);
613
- this._updateSource();
614
- }
615
- /** Convenience to set a renderer on a sublayer */
616
- setLayerRenderer(layerId, renderer) {
617
- this.setLayerDrawingInfo(layerId, { renderer });
618
- }
619
- /** Show/hide a sublayer via dynamicLayers */
620
- setLayerVisibility(layerId, visible) {
621
- const current = this.esriServiceOptions.dynamicLayers || [];
622
- const next = Array.isArray(current) ? [...current] : [];
623
- const idx = next.findIndex(l => l.id === layerId);
624
- if (idx >= 0) {
625
- next[idx] = { ...next[idx], visible };
626
- }
627
- else {
628
- next.push({ id: layerId, visible });
629
- }
630
- // Ensure all visible layers are included
631
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(next);
632
- this._updateSource();
633
- }
634
- /** Set a definitionExpression for a sublayer, applied server-side */
635
- setLayerDefinition(layerId, definitionExpression) {
636
- const current = this.esriServiceOptions.dynamicLayers || [];
637
- const next = Array.isArray(current) ? [...current] : [];
638
- const idx = next.findIndex(l => l.id === layerId);
639
- if (idx >= 0) {
640
- next[idx] = { ...next[idx], definitionExpression };
641
- }
642
- else {
643
- next.push({ id: layerId, definitionExpression });
644
- }
645
- // Ensure all visible layers are included
646
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(next);
647
- this._updateSource();
648
- }
649
- // Build a SQL where clause and apply as definitionExpression
650
- setLayerFilter(layerId, filter) {
651
- const where = this._buildWhere(filter);
652
- if (where)
653
- this.setLayerDefinition(layerId, where);
654
- }
655
- _escapeValue(val) {
656
- if (val === null)
657
- return 'NULL';
658
- if (val instanceof Date)
659
- return `${val.valueOf()}`; // epoch ms for time-enabled services
660
- if (typeof val === 'number')
661
- return `${val}`;
662
- if (typeof val === 'boolean')
663
- return val ? '1' : '0';
664
- const s = String(val).replace(/'/g, "''");
665
- return `'${s}'`;
666
- }
667
- // Very small, pragmatic builder that covers common cases in types.ts
668
- _isGroupFilter(f) {
669
- return (typeof f !== 'string' &&
670
- 'op' in f &&
671
- (f.op === 'AND' || f.op === 'OR') &&
672
- 'filters' in f &&
673
- Array.isArray(f.filters));
674
- }
675
- _isBetweenFilter(f) {
676
- return (typeof f !== 'string' &&
677
- 'op' in f &&
678
- f.op === 'BETWEEN' &&
679
- 'field' in f &&
680
- typeof f.field === 'string' &&
681
- 'from' in f &&
682
- f.from !== undefined &&
683
- 'to' in f &&
684
- f.to !== undefined);
685
- }
686
- _isInFilter(f) {
687
- return (typeof f !== 'string' &&
688
- 'op' in f &&
689
- f.op === 'IN' &&
690
- 'field' in f &&
691
- typeof f.field === 'string' &&
692
- 'values' in f &&
693
- Array.isArray(f.values));
694
- }
695
- _isNullFilter(f) {
696
- return (typeof f !== 'string' &&
697
- 'op' in f &&
698
- (f.op === 'IS NULL' || f.op === 'IS NOT NULL') &&
699
- 'field' in f &&
700
- typeof f.field === 'string');
701
- }
702
- _isComparisonFilter(f) {
703
- return (typeof f !== 'string' &&
704
- 'field' in f &&
705
- typeof f.field === 'string' &&
706
- 'op' in f &&
707
- typeof f.op === 'string' &&
708
- 'value' in f &&
709
- f.value !== undefined);
710
- }
711
- _buildWhere(filter) {
712
- if (!filter)
713
- return undefined;
714
- if (typeof filter === 'string')
715
- return filter.trim();
716
- if (this._isBetweenFilter(filter)) {
717
- return `${filter.field} BETWEEN ${this._escapeValue(filter.from)} AND ${this._escapeValue(filter.to)}`;
718
- }
719
- if (this._isInFilter(filter)) {
720
- const vals = filter.values.map(v => this._escapeValue(v)).join(', ');
721
- return `${filter.field} IN (${vals})`;
722
- }
723
- if (this._isNullFilter(filter)) {
724
- return `${filter.field} ${filter.op}`;
725
- }
726
- if (this._isGroupFilter(filter)) {
727
- const built = filter.filters
728
- .map((f) => this._buildWhere(f))
729
- .filter((s) => Boolean(s));
730
- if (!built.length)
731
- return undefined;
732
- if (built.length === 1)
733
- return built[0];
734
- return `(${built.join(` ${filter.op} `)})`;
735
- }
736
- if (this._isComparisonFilter(filter)) {
737
- return `${filter.field} ${filter.op} ${this._escapeValue(filter.value)}`;
738
- }
739
- return undefined;
740
- }
741
531
  setLayers(arr) {
742
532
  this.esriServiceOptions.layers = arr;
743
533
  this._updateSource();
@@ -775,9 +565,7 @@ class DynamicMapService {
775
565
  return layersStr ? layersStr.replace('show', 'visible') : false;
776
566
  }
777
567
  identify(lnglat, returnGeometry = false) {
778
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
779
568
  const canvas = this._map.getCanvas();
780
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
781
569
  const bounds = this._map.getBounds().toArray();
782
570
  const params = new URLSearchParams({
783
571
  sr: '4326',
@@ -798,8 +586,6 @@ class DynamicMapService {
798
586
  });
799
587
  if (this._layerDefs)
800
588
  params.append('layerDefs', this._layerDefs);
801
- if (this._dynamicLayers)
802
- params.append('dynamicLayers', this._dynamicLayers);
803
589
  if (this._time)
804
590
  params.append('time', this._time);
805
591
  return new Promise((resolve, reject) => {
@@ -809,313 +595,6 @@ class DynamicMapService {
809
595
  .catch(error => reject(error));
810
596
  });
811
597
  }
812
- // ========================================
813
- // Advanced Features
814
- // ========================================
815
- /** Set labeling configuration for a sublayer */
816
- setLayerLabels(layerId, labelingInfo) {
817
- const current = this.esriServiceOptions.dynamicLayers || [];
818
- const next = Array.isArray(current) ? [...current] : [];
819
- const idx = next.findIndex(l => l.id === layerId);
820
- if (idx >= 0) {
821
- next[idx] = {
822
- ...next[idx],
823
- drawingInfo: {
824
- ...next[idx].drawingInfo,
825
- labelingInfo: [labelingInfo],
826
- },
827
- };
828
- }
829
- else {
830
- next.push({
831
- id: layerId,
832
- drawingInfo: { labelingInfo: [labelingInfo] },
833
- });
834
- }
835
- // Ensure all visible layers are included
836
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(next);
837
- this._updateSource();
838
- }
839
- /** Toggle label visibility for a sublayer */
840
- setLayerLabelsVisible(layerId, visible) {
841
- if (visible) {
842
- // If enabling labels but no labeling info exists, set a default
843
- const current = this.esriServiceOptions.dynamicLayers || [];
844
- const layer = Array.isArray(current) ? current.find(l => l.id === layerId) : null;
845
- if (!layer?.drawingInfo?.labelingInfo) {
846
- // Set a basic label configuration
847
- this.setLayerLabels(layerId, {
848
- labelExpression: '[OBJECTID]', // Default to object ID
849
- symbol: {
850
- type: 'esriTS',
851
- color: [0, 0, 0, 255],
852
- font: { family: 'Arial', size: 8 },
853
- },
854
- });
855
- }
856
- }
857
- else {
858
- // Remove labeling info to disable labels
859
- const current = this.esriServiceOptions.dynamicLayers || [];
860
- const next = Array.isArray(current) ? [...current] : [];
861
- const idx = next.findIndex(l => l.id === layerId);
862
- if (idx >= 0) {
863
- const drawingInfo = { ...next[idx].drawingInfo };
864
- delete drawingInfo.labelingInfo;
865
- next[idx] = { ...next[idx], drawingInfo };
866
- // Ensure all visible layers are included
867
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(next);
868
- this._updateSource();
869
- }
870
- }
871
- }
872
- /** Set time options for a time-enabled sublayer */
873
- setLayerTimeOptions(layerId, timeOptions) {
874
- const current = this.esriServiceOptions.dynamicLayers || [];
875
- const next = Array.isArray(current) ? [...current] : [];
876
- const idx = next.findIndex(l => l.id === layerId);
877
- if (idx >= 0) {
878
- next[idx] = { ...next[idx], layerTimeOptions: timeOptions };
879
- }
880
- else {
881
- next.push({ id: layerId, layerTimeOptions: timeOptions });
882
- }
883
- // Ensure all visible layers are included
884
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(next);
885
- this._updateSource();
886
- }
887
- /** Animate through time periods for time-enabled layers */
888
- async animateTime(options) {
889
- const { from, to, intervalMs, loop = false, onFrame, onComplete } = options;
890
- const totalDuration = to.getTime() - from.getTime();
891
- const steps = Math.ceil(totalDuration / intervalMs);
892
- return new Promise(resolve => {
893
- let currentStep = 0;
894
- const animate = () => {
895
- if (currentStep >= steps && !loop) {
896
- onComplete?.();
897
- resolve();
898
- return;
899
- }
900
- const progress = (currentStep % steps) / steps;
901
- const currentTime = new Date(from.getTime() + progress * totalDuration);
902
- // Update service time extent
903
- this.esriServiceOptions.from = currentTime;
904
- this.esriServiceOptions.to = currentTime;
905
- this._updateSource();
906
- onFrame?.(currentTime, progress);
907
- currentStep++;
908
- setTimeout(animate, intervalMs);
909
- };
910
- animate();
911
- });
912
- }
913
- /** Get statistics for a sublayer */
914
- async getLayerStatistics(layerId, statisticFields, options = {}) {
915
- const queryUrl = `${this.esriServiceOptions.url}/${layerId}/query`;
916
- const params = new URLSearchParams({
917
- f: 'json',
918
- where: options.where || '1=1',
919
- outStatistics: JSON.stringify(statisticFields),
920
- returnGeometry: 'false',
921
- });
922
- if (options.groupByFieldsForStatistics) {
923
- params.append('groupByFieldsForStatistics', options.groupByFieldsForStatistics);
924
- }
925
- const response = await fetch(`${queryUrl}?${params.toString()}`);
926
- const data = await response.json();
927
- if (data.error) {
928
- throw new Error(`Statistics query failed: ${data.error.message}`);
929
- }
930
- return data.features || [];
931
- }
932
- /** Query features from a specific sublayer */
933
- async queryLayerFeatures(layerId, options = {}) {
934
- const queryUrl = `${this.esriServiceOptions.url}/${layerId}/query`;
935
- const params = new URLSearchParams({
936
- f: 'json',
937
- where: options.where || '1=1',
938
- returnGeometry: options.returnGeometry !== false ? 'true' : 'false',
939
- outFields: Array.isArray(options.outFields)
940
- ? options.outFields.join(',')
941
- : options.outFields || '*',
942
- });
943
- if (options.geometry) {
944
- params.append('geometry', JSON.stringify(options.geometry));
945
- params.append('geometryType', options.geometryType || 'esriGeometryEnvelope');
946
- params.append('spatialRel', options.spatialRel || 'esriSpatialRelIntersects');
947
- }
948
- if (options.orderByFields) {
949
- params.append('orderByFields', options.orderByFields);
950
- }
951
- if (options.resultOffset) {
952
- params.append('resultOffset', options.resultOffset.toString());
953
- }
954
- if (options.resultRecordCount) {
955
- params.append('resultRecordCount', options.resultRecordCount.toString());
956
- }
957
- if (options.returnCountOnly) {
958
- params.append('returnCountOnly', 'true');
959
- }
960
- if (options.returnIdsOnly) {
961
- params.append('returnIdsOnly', 'true');
962
- }
963
- const response = await fetch(`${queryUrl}?${params.toString()}`);
964
- const data = await response.json();
965
- if (data.error) {
966
- throw new Error(`Layer query failed: ${data.error.message}`);
967
- }
968
- return data;
969
- }
970
- /** Export high-resolution map image */
971
- async exportMapImage(options) {
972
- const exportUrl = `${this.esriServiceOptions.url}/export`;
973
- const params = new URLSearchParams({
974
- f: 'image',
975
- bbox: options.bbox.join(','),
976
- size: options.size.join(','),
977
- format: options.format || 'png24',
978
- transparent: options.transparent !== false ? 'true' : 'false',
979
- dpi: (options.dpi || 96).toString(),
980
- bboxSR: (options.bboxSR || 3857).toString(),
981
- imageSR: (options.imageSR || 3857).toString(),
982
- });
983
- if (options.layerDefs) {
984
- params.append('layerDefs', JSON.stringify(options.layerDefs));
985
- }
986
- if (options.dynamicLayers) {
987
- const normalized = this._ensureAllVisibleLayers(options.dynamicLayers);
988
- params.append('dynamicLayers', JSON.stringify(normalized));
989
- }
990
- if (options.gdbVersion) {
991
- params.append('gdbVersion', options.gdbVersion);
992
- }
993
- if (options.historicMoment) {
994
- params.append('historicMoment', options.historicMoment.toString());
995
- }
996
- const response = await fetch(`${exportUrl}?${params.toString()}`);
997
- if (!response.ok) {
998
- throw new Error(`Export failed: ${response.statusText}`);
999
- }
1000
- return response.blob();
1001
- }
1002
- /** Generate legend information for layers */
1003
- async generateLegend(layerIds) {
1004
- const legendUrl = `${this.esriServiceOptions.url}/legend`;
1005
- const params = new URLSearchParams({
1006
- f: 'json',
1007
- });
1008
- if (layerIds?.length) {
1009
- params.append('layers', layerIds.join(','));
1010
- }
1011
- const response = await fetch(`${legendUrl}?${params.toString()}`);
1012
- const data = await response.json();
1013
- if (data.error) {
1014
- throw new Error(`Legend generation failed: ${data.error.message}`);
1015
- }
1016
- return data.layers || [];
1017
- }
1018
- /** Get detailed information about a specific layer */
1019
- async getLayerInfo(layerId) {
1020
- const layerUrl = `${this.esriServiceOptions.url}/${layerId}`;
1021
- const params = new URLSearchParams({ f: 'json' });
1022
- const response = await fetch(`${layerUrl}?${params.toString()}`);
1023
- const data = await response.json();
1024
- if (data.error) {
1025
- throw new Error(`Layer info request failed: ${data.error.message}`);
1026
- }
1027
- return data;
1028
- }
1029
- /** Get field information for a layer */
1030
- async getLayerFields(layerId) {
1031
- const layerInfo = await this.getLayerInfo(layerId);
1032
- return layerInfo.fields || [];
1033
- }
1034
- /** Get spatial extent of a layer */
1035
- async getLayerExtent(layerId) {
1036
- const layerInfo = await this.getLayerInfo(layerId);
1037
- if (!layerInfo.extent) {
1038
- throw new Error(`No extent available for layer ${layerId}`);
1039
- }
1040
- return layerInfo.extent;
1041
- }
1042
- /** Discover all layers in the service */
1043
- async discoverLayers() {
1044
- const serviceUrl = this.esriServiceOptions.url;
1045
- const params = new URLSearchParams({ f: 'json' });
1046
- const response = await fetch(`${serviceUrl}?${params.toString()}`);
1047
- const data = await response.json();
1048
- if (data.error) {
1049
- throw new Error(`Service discovery failed: ${data.error.message}`);
1050
- }
1051
- return data.layers || [];
1052
- }
1053
- /** Apply multiple layer operations in a single update */
1054
- setBulkLayerProperties(operations) {
1055
- const current = this.esriServiceOptions.dynamicLayers || [];
1056
- const next = Array.isArray(current) ? [...current] : [];
1057
- // Process all operations
1058
- for (const op of operations) {
1059
- const idx = next.findIndex(l => l.id === op.layerId);
1060
- const layer = idx >= 0 ? { ...next[idx] } : { id: op.layerId };
1061
- switch (op.operation) {
1062
- case 'visibility':
1063
- layer.visible = op.value;
1064
- break;
1065
- case 'renderer':
1066
- layer.drawingInfo = { ...layer.drawingInfo, renderer: op.value };
1067
- break;
1068
- case 'definition':
1069
- layer.definitionExpression = op.value;
1070
- break;
1071
- case 'filter': {
1072
- const where = this._buildWhere(op.value);
1073
- if (where)
1074
- layer.definitionExpression = where;
1075
- break;
1076
- }
1077
- case 'labels':
1078
- layer.drawingInfo = {
1079
- ...layer.drawingInfo,
1080
- labelingInfo: op.value,
1081
- };
1082
- break;
1083
- case 'time':
1084
- layer.layerTimeOptions = op.value;
1085
- break;
1086
- }
1087
- if (idx >= 0) {
1088
- next[idx] = layer;
1089
- }
1090
- else {
1091
- next.push(layer);
1092
- }
1093
- }
1094
- // Ensure all visible layers are included
1095
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(next);
1096
- this._updateSource();
1097
- }
1098
- /** Begin a batch update transaction */
1099
- beginUpdate() {
1100
- const current = this.esriServiceOptions.dynamicLayers || [];
1101
- this._pendingUpdates = Array.isArray(current) ? [...current] : [];
1102
- }
1103
- /** Commit all pending updates */
1104
- commitUpdate() {
1105
- if (this._pendingUpdates) {
1106
- this.esriServiceOptions.dynamicLayers = this._ensureAllVisibleLayers(this._pendingUpdates);
1107
- this._pendingUpdates = null;
1108
- this._updateSource();
1109
- }
1110
- }
1111
- /** Rollback pending updates */
1112
- rollbackUpdate() {
1113
- this._pendingUpdates = null;
1114
- }
1115
- /** Check if currently in a transaction */
1116
- get isInTransaction() {
1117
- return this._pendingUpdates !== null;
1118
- }
1119
598
  update() {
1120
599
  this._updateSource();
1121
600
  }
@@ -1262,7 +741,6 @@ class ImageService {
1262
741
  this._defaultEsriOptions = {
1263
742
  layers: false,
1264
743
  layerDefs: false,
1265
- dynamicLayers: false,
1266
744
  format: 'jpgpng',
1267
745
  dpi: 96,
1268
746
  transparent: true,