@eeacms/volto-arcgis-block 0.1.478 → 0.1.480

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/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [0.1.480](https://github.com/eea/volto-arcgis-block/compare/0.1.479...0.1.480) - 10 September 2026
8
+
9
+ ### [0.1.479](https://github.com/eea/volto-arcgis-block/compare/0.1.478...0.1.479) - 8 September 2026
10
+
11
+ #### :hammer_and_wrench: Others
12
+
13
+ - (lint): lint and prettified [Unai Bolivar - [`89001ca`](https://github.com/eea/volto-arcgis-block/commit/89001ca4c7c5bad39c2eeaed0ffd03ecd3fcfbe1)]
14
+ - (lint): lint and prettified [Unai Bolivar - [`f3a2e36`](https://github.com/eea/volto-arcgis-block/commit/f3a2e3602eba3e5279d2a2e080cf8f52cc26690d)]
15
+ - (lint): lint and prettified [Unai Bolivar - [`3ea38aa`](https://github.com/eea/volto-arcgis-block/commit/3ea38aa798a8ac6df3db03651f8f9e02c1b5d9a5)]
16
+ - (lint): lint and prettified [Unai Bolivar - [`5d96946`](https://github.com/eea/volto-arcgis-block/commit/5d969465ba1e55a1048c647d121d82081677daa3)]
17
+ - (bug): finished implementing changes to hot spot widget [Unai Bolivar - [`2bf933b`](https://github.com/eea/volto-arcgis-block/commit/2bf933bc2e0ef57c0df2308ec90c903f643ee27f)]
18
+ - (bug): switched to drop down for the date selection in hot spot widget [Unai Bolivar - [`5c83990`](https://github.com/eea/volto-arcgis-block/commit/5c839901bbb0637a716aaac4f48011622b5325ca)]
19
+ - (bug): improve hotspot widget behavior for new json data. create a reference land cover selection box only for new data [Unai Bolivar - [`d73f58f`](https://github.com/eea/volto-arcgis-block/commit/d73f58ff1addcb06ac61e8947e64e34a2bc29647)]
20
+ - (bug): improve hotspot widget behavior for new json data [Unai Bolivar - [`643c95d`](https://github.com/eea/volto-arcgis-block/commit/643c95d93f375b90c39e16774b866daffa5f11aa)]
21
+ - (bug): improve hotspot server calls to avoid sql injection rejection warning from servers [Unai Bolivar - [`4c76cbf`](https://github.com/eea/volto-arcgis-block/commit/4c76cbf1d78ac2db6225a1b001e02badbd852133)]
7
22
  ### [0.1.478](https://github.com/eea/volto-arcgis-block/compare/0.1.477...0.1.478) - 3 September 2026
8
23
 
9
24
  #### :house: Internal changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-arcgis-block",
3
- "version": "0.1.478",
3
+ "version": "0.1.480",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -18,8 +18,10 @@ class HotspotWidget extends React.Component {
18
18
  showMapMenu: false,
19
19
  activeLayers: {},
20
20
  selectedArea: null,
21
+ referenceLcYear: null,
21
22
  lcYear: null,
22
23
  lccYear: null,
24
+ hasMultipleLcDates: false,
23
25
  activeLayersArray: [],
24
26
  };
25
27
  this.menuClass =
@@ -46,8 +48,10 @@ class HotspotWidget extends React.Component {
46
48
  this.handleApplyFilter = this.handleApplyFilter.bind(this);
47
49
  this.filteredLayersToHotspotData =
48
50
  this.filteredLayersToHotspotData.bind(this);
51
+ this.resetHotspotWidgetFilters = this.resetHotspotWidgetFilters.bind(this);
49
52
  this.mapCfg = this.props.mapCfg;
50
53
  this.selectedArea = null;
54
+ this.referenceLcYear = null;
51
55
  this.lcYear = null;
52
56
  this.lccYear = null;
53
57
  this.urls = this.props.urls;
@@ -56,6 +60,250 @@ class HotspotWidget extends React.Component {
56
60
  this._isMounted = false;
57
61
  }
58
62
 
63
+ parseKeymapInfo(rawKeymapInfo) {
64
+ if (typeof rawKeymapInfo === 'string') {
65
+ try {
66
+ return JSON.parse(rawKeymapInfo) || {};
67
+ } catch (e) {
68
+ return {};
69
+ }
70
+ }
71
+ if (rawKeymapInfo && typeof rawKeymapInfo === 'object') {
72
+ return rawKeymapInfo;
73
+ }
74
+ return {};
75
+ }
76
+
77
+ getDateOptionsForNode(node) {
78
+ const keyMapInfoObj = this.parseKeymapInfo(node?.keymap_info);
79
+ let lccDateList = [];
80
+ let lcDateList = [];
81
+ let lccDatesByLcYear = {};
82
+
83
+ if (Array.isArray(keyMapInfoObj.dates)) {
84
+ keyMapInfoObj.dates.forEach((entry) => {
85
+ const lccDate = Number(
86
+ entry && typeof entry === 'object' ? entry?.date : entry,
87
+ );
88
+ const lcDate = Number(
89
+ entry && typeof entry === 'object' ? entry?.lc_date : undefined,
90
+ );
91
+ if (Number.isFinite(lccDate)) {
92
+ lccDateList.push(lccDate);
93
+ }
94
+ if (Number.isFinite(lcDate)) {
95
+ lcDateList.push(lcDate);
96
+ if (!lccDatesByLcYear[lcDate]) {
97
+ lccDatesByLcYear[lcDate] = [];
98
+ }
99
+ if (Number.isFinite(lccDate)) {
100
+ lccDatesByLcYear[lcDate].push(lccDate);
101
+ }
102
+ }
103
+ });
104
+ }
105
+
106
+ if (Array.isArray(keyMapInfoObj.multiple_lc_dates)) {
107
+ lcDateList = lcDateList.concat(
108
+ keyMapInfoObj.multiple_lc_dates
109
+ .map((yearEntry) =>
110
+ Number(
111
+ yearEntry && typeof yearEntry === 'object'
112
+ ? yearEntry?.date
113
+ : yearEntry,
114
+ ),
115
+ )
116
+ .filter((year) => Number.isFinite(year)),
117
+ );
118
+ }
119
+
120
+ const dynamicYearValues = Object.keys(keyMapInfoObj)
121
+ .filter((key) => /^year\d+$/.test(key))
122
+ .map((key) => Number(keyMapInfoObj[key]))
123
+ .filter((year) => Number.isFinite(year));
124
+ if (dynamicYearValues.length) {
125
+ lccDateList = lccDateList.concat(dynamicYearValues);
126
+ }
127
+
128
+ const presentLcYearFromKeymap = Number(keyMapInfoObj.year_present_lc);
129
+ if (Number.isFinite(presentLcYearFromKeymap)) {
130
+ lcDateList.push(presentLcYearFromKeymap);
131
+ }
132
+
133
+ if (!lccDateList.length && Number.isFinite(Number(node?.lcc_year))) {
134
+ lccDateList = [Number(node?.lcc_year)];
135
+ }
136
+ if (!lcDateList.length && Number.isFinite(Number(node?.present_lc_year))) {
137
+ lcDateList = [Number(node?.present_lc_year)];
138
+ }
139
+
140
+ lccDateList = Array.from(new Set(lccDateList)).sort((a, b) => a - b);
141
+ lcDateList = Array.from(new Set(lcDateList)).sort((a, b) => a - b);
142
+
143
+ Object.keys(lccDatesByLcYear).forEach((lcDateKey) => {
144
+ lccDatesByLcYear[lcDateKey] = Array.from(
145
+ new Set(lccDatesByLcYear[lcDateKey]),
146
+ ).sort((a, b) => a - b);
147
+ });
148
+
149
+ const mappedLcYears = Object.keys(lccDatesByLcYear).map((year) =>
150
+ Number(year),
151
+ );
152
+ if (!mappedLcYears.length && lcDateList.length && lccDateList.length) {
153
+ const lccYearsWithoutLcYears = lccDateList.filter(
154
+ (year) => !lcDateList.includes(year),
155
+ );
156
+ if (lccYearsWithoutLcYears.length) {
157
+ lccDateList = lccYearsWithoutLcYears;
158
+ }
159
+ if (lcDateList.length === 1) {
160
+ lccDatesByLcYear[lcDateList[0]] = [...lccDateList];
161
+ }
162
+ }
163
+
164
+ return {
165
+ keyMapInfoObj,
166
+ lccDateList,
167
+ lcDateList,
168
+ lccDatesByLcYear,
169
+ };
170
+ }
171
+
172
+ getSelectedNodeByArea(selectedArea) {
173
+ if (!selectedArea || !Array.isArray(this.dataJSONNames)) {
174
+ return null;
175
+ }
176
+
177
+ return this.dataJSONNames.find(
178
+ (entry) => entry?.node?.klc_name === selectedArea,
179
+ )?.node;
180
+ }
181
+
182
+ isReferenceSelectionKlcCode(klcCode) {
183
+ return klcCode === 'CAF_02' || klcCode === 'CAF_05';
184
+ }
185
+
186
+ getReferenceLcYearSelection(lcDateList) {
187
+ const selectedReferenceLcYear = Number(this.state.referenceLcYear);
188
+ if (
189
+ Number.isFinite(selectedReferenceLcYear) &&
190
+ lcDateList.includes(selectedReferenceLcYear)
191
+ ) {
192
+ return selectedReferenceLcYear;
193
+ }
194
+ return null;
195
+ }
196
+
197
+ setPresentLandCoverVisibility(shouldShow) {
198
+ const presentLandCoverContainer = this.container.current?.querySelector(
199
+ '.presentLandCoverContainer',
200
+ );
201
+ if (presentLandCoverContainer) {
202
+ presentLandCoverContainer.style.display = shouldShow ? 'block' : 'none';
203
+ }
204
+ }
205
+
206
+ isHotspotLayerKey(layerKey) {
207
+ if (typeof layerKey !== 'string') return false;
208
+ return (
209
+ layerKey.includes('all_present_lc_') ||
210
+ layerKey.includes('all_lcc_') ||
211
+ layerKey.includes('cop_klc') ||
212
+ layerKey.includes('protected_areas') ||
213
+ layerKey.endsWith('_filter')
214
+ );
215
+ }
216
+
217
+ removeLayerFromMap(layer) {
218
+ if (!layer || !this.props.map) return;
219
+ try {
220
+ this.props.map.remove(layer);
221
+ } catch (e) {}
222
+ if (layer.visible !== undefined) {
223
+ layer.visible = false;
224
+ }
225
+ }
226
+
227
+ clearHotspotLayersFromMap() {
228
+ const layerRefs = [];
229
+ if (this.layers && typeof this.layers === 'object') {
230
+ Object.keys(this.layers).forEach((layerKey) => {
231
+ if (this.isHotspotLayerKey(layerKey) && this.layers[layerKey]) {
232
+ layerRefs.push(this.layers[layerKey]);
233
+ }
234
+ });
235
+ }
236
+
237
+ const hotspotData = this.props.hotspotData || {};
238
+ const activeLayers = hotspotData.activeLayers || {};
239
+ const filteredLayers = hotspotData.filteredLayers || {};
240
+
241
+ Object.keys(activeLayers).forEach((layerKey) => {
242
+ if (this.isHotspotLayerKey(layerKey) && activeLayers[layerKey]) {
243
+ layerRefs.push(activeLayers[layerKey]);
244
+ }
245
+ });
246
+ Object.keys(filteredLayers).forEach((layerKey) => {
247
+ if (this.isHotspotLayerKey(layerKey) && filteredLayers[layerKey]) {
248
+ layerRefs.push(filteredLayers[layerKey]);
249
+ }
250
+ });
251
+
252
+ Array.from(new Set(layerRefs)).forEach((layer) => {
253
+ this.removeLayerFromMap(layer);
254
+ });
255
+ }
256
+
257
+ resetHotspotViewState() {
258
+ if (this.props.view && this.props.view.popup) {
259
+ this.props.view.popup.close();
260
+ }
261
+ if (this.props.view && this.props.view.graphics) {
262
+ this.props.view.graphics.removeAll();
263
+ }
264
+ }
265
+
266
+ resetHotspotWidgetFilters() {
267
+ const selectBox = document.getElementById('select-klc-area');
268
+ const selectBoxLcTime = document.getElementById('select-klc-lcTime');
269
+ const selectBoxLccTime = document.getElementById('select-klc-lccTime');
270
+
271
+ if (selectBox) {
272
+ selectBox.value = 'default';
273
+ }
274
+
275
+ if (selectBoxLcTime) {
276
+ this.removeOptions(selectBoxLcTime);
277
+ selectBoxLcTime.options.add(
278
+ new Option('Select a year', 'default', true, true),
279
+ );
280
+ selectBoxLcTime.options[0].disabled = true;
281
+ }
282
+
283
+ if (selectBoxLccTime) {
284
+ this.removeOptions(selectBoxLccTime);
285
+ selectBoxLccTime.options.add(
286
+ new Option('Select a year', 'default', true, true),
287
+ );
288
+ selectBoxLccTime.options[0].disabled = true;
289
+ }
290
+
291
+ this.setPresentLandCoverVisibility(false);
292
+
293
+ this.selectedArea = null;
294
+ this.referenceLcYear = null;
295
+ this.lcYear = null;
296
+ this.lccYear = null;
297
+
298
+ this.setState({
299
+ selectedArea: null,
300
+ referenceLcYear: null,
301
+ lcYear: null,
302
+ lccYear: null,
303
+ hasMultipleLcDates: false,
304
+ });
305
+ }
306
+
59
307
  loader() {
60
308
  return loadModules([
61
309
  'esri/layers/WMSLayer',
@@ -185,8 +433,7 @@ class HotspotWidget extends React.Component {
185
433
  }
186
434
 
187
435
  buildCqlFilter(klcCode, date) {
188
- const baseFilter =
189
- "klc_code LIKE '" + klcCode + "' AND in_pa LIKE 'not_defined'";
436
+ const baseFilter = "klc_code='" + klcCode + "' AND in_pa='not_defined'";
190
437
  if (!Number.isFinite(Number(date))) {
191
438
  return baseFilter;
192
439
  }
@@ -208,38 +455,13 @@ class HotspotWidget extends React.Component {
208
455
  };
209
456
  }
210
457
 
211
- resolveLccDateOptions(
212
- klcCode,
213
- selectedLcYear,
214
- lccDatesByLcYear,
215
- lccDateList,
216
- ) {
217
- const klcLcDateMap = {
218
- CAF_02: {
219
- 2016: [2000, 2019],
220
- 2019: [2024],
221
- },
222
- CAF_05: {
223
- 2015: [2000, 2019],
224
- 2019: [2024],
225
- },
226
- };
227
-
228
- const mappedByKlc = klcLcDateMap[klcCode] || null;
229
- if (mappedByKlc && Number.isFinite(Number(selectedLcYear))) {
230
- const mapped = mappedByKlc[Number(selectedLcYear)];
231
- if (Array.isArray(mapped) && mapped.length) {
232
- return Array.from(new Set(mapped)).sort((a, b) => a - b);
233
- }
234
- }
235
-
458
+ getLccDateOptionsFromData(selectedLcYear, lccDatesByLcYear, lccDateList) {
236
459
  const mappedByData = Number.isFinite(Number(selectedLcYear))
237
460
  ? lccDatesByLcYear[Number(selectedLcYear)]
238
461
  : null;
239
462
  if (Array.isArray(mappedByData) && mappedByData.length) {
240
463
  return mappedByData;
241
464
  }
242
-
243
465
  return lccDateList;
244
466
  }
245
467
 
@@ -358,6 +580,11 @@ class HotspotWidget extends React.Component {
358
580
  }
359
581
 
360
582
  async handleApplyFilter(typeFilter) {
583
+ await Promise.all([this.getLayerParameters(), this.getBBoxData()]);
584
+ this.clearHotspotLayersFromMap();
585
+ this.resetHotspotViewState();
586
+ this.layerModelInit();
587
+
361
588
  let typeLegend;
362
589
  let title;
363
590
  let activeLayers =
@@ -495,7 +722,7 @@ class HotspotWidget extends React.Component {
495
722
  } else {
496
723
  this.esriLayer_klc.customLayerParameters =
497
724
  this.buildWmsCustomLayerParameters(
498
- "klc_code LIKE '" + this.dataKlc_code + "'",
725
+ "klc_code='" + this.dataKlc_code + "'",
499
726
  );
500
727
  }
501
728
  filterLayer = this.esriLayer_klc;
@@ -519,7 +746,7 @@ class HotspotWidget extends React.Component {
519
746
  } else {
520
747
  this.esriLayer_pa.customLayerParameters =
521
748
  this.buildWmsCustomLayerParameters(
522
- "klc_code LIKE '" + this.dataKlc_code + "'",
749
+ "klc_code='" + this.dataKlc_code + "'",
523
750
  );
524
751
  }
525
752
  filterLayer = this.esriLayer_pa;
@@ -537,8 +764,6 @@ class HotspotWidget extends React.Component {
537
764
  if (layerId !== undefined) this.layers[layerId].visible = false;
538
765
  let layer = this.props.map.findLayerById(layerId);
539
766
  if (layer !== undefined) {
540
- layer.clear();
541
- layer.destroy();
542
767
  this.props.map.remove(layer);
543
768
  }
544
769
  });
@@ -549,8 +774,6 @@ class HotspotWidget extends React.Component {
549
774
  if (layerId !== undefined) this.layers[layerId].visible = false;
550
775
  let layer = this.props.map.findLayerById(layerId);
551
776
  if (layer !== undefined) {
552
- layer.clear();
553
- layer.destroy();
554
777
  this.props.map.remove(layer);
555
778
  }
556
779
  });
@@ -628,6 +851,7 @@ class HotspotWidget extends React.Component {
628
851
 
629
852
  openMenu() {
630
853
  if (this.state.showMapMenu) {
854
+ this.resetHotspotWidgetFilters();
631
855
  this.props.mapViewer.setActiveWidget();
632
856
  this.container.current.querySelector('.right-panel').style.display =
633
857
  'none';
@@ -660,7 +884,7 @@ class HotspotWidget extends React.Component {
660
884
  const url =
661
885
  window.location.href.replace(window.location.pathname.substring(3), '') +
662
886
  this.props.urls.all_geo_klc;
663
- fetch(url)
887
+ return fetch(url)
664
888
  .then((data) => {
665
889
  if (data.status === 200) {
666
890
  return data.json();
@@ -680,18 +904,24 @@ class HotspotWidget extends React.Component {
680
904
  this.props.hotspotData && this.props.hotspotData['activeLayers']
681
905
  ? Object.keys(this.props.hotspotData['activeLayers'])
682
906
  : [];
907
+ const hasActivePresentLcLayer = activeLayers.some(
908
+ (layer) =>
909
+ layer.includes('all_present_lc_a_pol') ||
910
+ layer.includes('all_present_lc_b_pol') ||
911
+ layer.includes('lc_filter'),
912
+ );
913
+ const hasActiveLccLayer = activeLayers.some(
914
+ (layer) =>
915
+ layer.includes('all_lcc_a_pol') ||
916
+ layer.includes('all_lcc_b_pol') ||
917
+ layer.includes('lcc_filter'),
918
+ );
683
919
 
684
- if (
685
- this.container.current.querySelector('.presentLandCoverContainer').style
686
- .display === 'block'
687
- ) {
920
+ if (hasActivePresentLcLayer) {
688
921
  typeFilter.push('lc');
689
922
  }
690
923
 
691
- if (
692
- this.container.current.querySelector('.landCoverChangeContainer').style
693
- .display === 'block'
694
- ) {
924
+ if (hasActiveLccLayer) {
695
925
  typeFilter.push('lcc');
696
926
  }
697
927
  activeLayers.forEach((layer) => {
@@ -789,22 +1019,16 @@ class HotspotWidget extends React.Component {
789
1019
  selectBoxLccTime = document.getElementById('select-klc-lccTime');
790
1020
  selectBoxLcTime = document.getElementById('select-klc-lcTime');
791
1021
 
1022
+ let hasMultipleLcDatesForSelection = false;
1023
+ let hasSelectedAreaOption = false;
1024
+
792
1025
  //this.selectedArea = selectedOption;
793
1026
 
794
1027
  for (let i = 0; i < data.length; i++) {
795
1028
  var option = data[i].node.klc_name;
796
1029
 
797
1030
  let rawKeymapInfo = data[i].node.keymap_info;
798
- let keyMapInfoObj = {};
799
- if (typeof rawKeymapInfo === 'string') {
800
- try {
801
- keyMapInfoObj = JSON.parse(rawKeymapInfo) || {};
802
- } catch (e) {
803
- keyMapInfoObj = {};
804
- }
805
- } else if (rawKeymapInfo && typeof rawKeymapInfo === 'object') {
806
- keyMapInfoObj = rawKeymapInfo;
807
- }
1031
+ let keyMapInfoObj = this.parseKeymapInfo(rawKeymapInfo);
808
1032
 
809
1033
  if (keyMapInfoObj.b_classes === true) {
810
1034
  modularKLCAreas.push(option);
@@ -830,102 +1054,47 @@ class HotspotWidget extends React.Component {
830
1054
  selectBoxLccTime.options[0].disabled = true;
831
1055
  }
832
1056
 
833
- let lccDateList = [];
834
- let lcDateList = [];
835
- let lccDatesByLcYear = {};
836
-
837
- if (Array.isArray(keyMapInfoObj.dates)) {
838
- keyMapInfoObj.dates.forEach((entry) => {
839
- const lccDate = Number(
840
- entry && typeof entry === 'object' ? entry?.date : entry,
841
- );
842
- const lcDate = Number(
843
- entry && typeof entry === 'object' ? entry?.lc_date : undefined,
844
- );
845
- if (Number.isFinite(lccDate)) {
846
- lccDateList.push(lccDate);
847
- }
848
- if (Number.isFinite(lcDate)) {
849
- lcDateList.push(lcDate);
850
- if (!lccDatesByLcYear[lcDate]) {
851
- lccDatesByLcYear[lcDate] = [];
852
- }
853
- if (Number.isFinite(lccDate)) {
854
- lccDatesByLcYear[lcDate].push(lccDate);
855
- }
856
- }
857
- });
858
- }
859
-
860
- if (Array.isArray(keyMapInfoObj.multiple_lc_dates)) {
861
- lcDateList = lcDateList.concat(
862
- keyMapInfoObj.multiple_lc_dates
863
- .map((yearEntry) =>
864
- Number(
865
- yearEntry && typeof yearEntry === 'object'
866
- ? yearEntry?.date
867
- : yearEntry,
868
- ),
869
- )
870
- .filter((year) => Number.isFinite(year)),
871
- );
872
- }
1057
+ const { lccDateList, lcDateList, lccDatesByLcYear } =
1058
+ this.getDateOptionsForNode(data[i].node);
873
1059
 
874
- const dynamicYearValues = Object.keys(keyMapInfoObj)
875
- .filter((key) => /^year\d+$/.test(key))
876
- .map((key) => Number(keyMapInfoObj[key]))
877
- .filter((year) => Number.isFinite(year));
878
- if (dynamicYearValues.length) {
879
- lccDateList = lccDateList.concat(dynamicYearValues);
880
- }
881
-
882
- const presentLcYearFromKeymap = Number(keyMapInfoObj.year_present_lc);
883
- if (Number.isFinite(presentLcYearFromKeymap)) {
884
- lcDateList.push(presentLcYearFromKeymap);
885
- }
886
-
887
- if (
888
- !lccDateList.length &&
889
- Number.isFinite(Number(data[i].node.lcc_year))
890
- ) {
891
- lccDateList = [Number(data[i].node.lcc_year)];
892
- }
893
- if (
894
- !lcDateList.length &&
895
- Number.isFinite(Number(data[i].node.present_lc_year))
896
- ) {
897
- lcDateList = [Number(data[i].node.present_lc_year)];
898
- }
1060
+ const isReferenceSelectionArea = this.isReferenceSelectionKlcCode(
1061
+ data[i].node.klc_code,
1062
+ );
1063
+ const selectedReferenceLcYear = isReferenceSelectionArea
1064
+ ? this.getReferenceLcYearSelection(lcDateList)
1065
+ : null;
899
1066
 
900
- lccDateList = Array.from(new Set(lccDateList)).sort((a, b) => a - b);
901
- lcDateList = Array.from(new Set(lcDateList)).sort((a, b) => a - b);
1067
+ hasMultipleLcDatesForSelection = lcDateList.length > 1;
1068
+ hasSelectedAreaOption = true;
902
1069
 
903
- Object.keys(lccDatesByLcYear).forEach((lcDateKey) => {
904
- lccDatesByLcYear[lcDateKey] = Array.from(
905
- new Set(lccDatesByLcYear[lcDateKey]),
906
- ).sort((a, b) => a - b);
907
- });
1070
+ const lcDateOptionsToUse =
1071
+ isReferenceSelectionArea && Number.isFinite(selectedReferenceLcYear)
1072
+ ? [selectedReferenceLcYear]
1073
+ : isReferenceSelectionArea
1074
+ ? []
1075
+ : lcDateList;
908
1076
 
909
- lcDateList.forEach((element) => {
1077
+ lcDateOptionsToUse.forEach((element) => {
910
1078
  selectBoxLcTime.options.add(new Option(element, element, element));
911
1079
  });
912
1080
 
913
- if (this.state.lcYear !== null) {
914
- const hasLcYearOption = Array.from(selectBoxLcTime.options).some(
915
- (option) => option.value === this.state.lcYear,
916
- );
917
- selectBoxLcTime.value = hasLcYearOption
918
- ? this.state.lcYear
919
- : 'default';
920
- }
921
-
922
- const selectedLcYear = Number(this.state.lcYear);
923
- const lccOptionsToUse = this.resolveLccDateOptions(
924
- data[i].node.klc_code,
925
- selectedLcYear,
926
- lccDatesByLcYear,
927
- lccDateList,
928
- );
1081
+ const selectedLcYear =
1082
+ isReferenceSelectionArea && Number.isFinite(selectedReferenceLcYear)
1083
+ ? selectedReferenceLcYear
1084
+ : Number(selectBoxLcTime.value);
1085
+ const lccOptionsToUse = hasMultipleLcDatesForSelection
1086
+ ? Number.isFinite(selectedLcYear)
1087
+ ? this.getLccDateOptionsFromData(
1088
+ selectedLcYear,
1089
+ lccDatesByLcYear,
1090
+ lccDateList,
1091
+ )
1092
+ : []
1093
+ : this.getLccDateOptionsFromData(
1094
+ selectedLcYear,
1095
+ lccDatesByLcYear,
1096
+ lccDateList,
1097
+ );
929
1098
 
930
1099
  lccOptionsToUse.forEach((element) => {
931
1100
  selectBoxLccTime.options.add(new Option(element, element, element));
@@ -944,12 +1113,14 @@ class HotspotWidget extends React.Component {
944
1113
  );
945
1114
  selectBox.options[0].disabled = true;
946
1115
  }
1116
+ let hasDatasetSpecificKlcOptions = false;
947
1117
  if (activeLayers.length) {
948
1118
  for (let a = 0; a < activeLayers.length; a++) {
949
1119
  if (
950
1120
  activeLayers[a].includes('all_lcc_b_pol') ||
951
1121
  activeLayers[a].includes('all_present_lc_b_pol')
952
1122
  ) {
1123
+ hasDatasetSpecificKlcOptions = true;
953
1124
  for (let i = 0; i < modularKLCAreas.length; i++) {
954
1125
  let option = modularKLCAreas[i];
955
1126
  selectBox.options.add(new Option(option, option, option));
@@ -960,22 +1131,6 @@ class HotspotWidget extends React.Component {
960
1131
  continue;
961
1132
  } else {
962
1133
  selectBox.value = this.state.selectedArea;
963
- if (this.state.lcYear !== null) {
964
- const hasLcYearOption = Array.from(
965
- selectBoxLcTime.options,
966
- ).some((option) => option.value === this.state.lcYear);
967
- selectBoxLcTime.value = hasLcYearOption
968
- ? this.state.lcYear
969
- : 'default';
970
- }
971
- if (this.state.lccYear !== null) {
972
- const hasLccYearOption = Array.from(
973
- selectBoxLccTime.options,
974
- ).some((option) => option.value === this.state.lccYear);
975
- selectBoxLccTime.value = hasLccYearOption
976
- ? this.state.lccYear
977
- : 'default';
978
- }
979
1134
  break; // move break statement inside the if block
980
1135
  }
981
1136
  }
@@ -984,6 +1139,7 @@ class HotspotWidget extends React.Component {
984
1139
  activeLayers[a].includes('all_lcc_a_pol') ||
985
1140
  activeLayers[a].includes('all_present_lc_a_pol')
986
1141
  ) {
1142
+ hasDatasetSpecificKlcOptions = true;
987
1143
  for (let i = 0; i < dichotomousKLCAreas.length; i++) {
988
1144
  let option = dichotomousKLCAreas[i];
989
1145
  selectBox.options.add(new Option(option, option, option));
@@ -994,29 +1150,15 @@ class HotspotWidget extends React.Component {
994
1150
  continue;
995
1151
  } else {
996
1152
  selectBox.value = this.state.selectedArea;
997
- if (this.state.lcYear !== null) {
998
- const hasLcYearOption = Array.from(
999
- selectBoxLcTime.options,
1000
- ).some((option) => option.value === this.state.lcYear);
1001
- selectBoxLcTime.value = hasLcYearOption
1002
- ? this.state.lcYear
1003
- : 'default';
1004
- }
1005
- if (this.state.lccYear !== null) {
1006
- const hasLccYearOption = Array.from(
1007
- selectBoxLccTime.options,
1008
- ).some((option) => option.value === this.state.lccYear);
1009
- selectBoxLccTime.value = hasLccYearOption
1010
- ? this.state.lccYear
1011
- : 'default';
1012
- }
1013
1153
  break;
1014
1154
  }
1015
1155
  }
1016
1156
  break;
1017
1157
  }
1018
1158
  }
1019
- } else if (selectBox) {
1159
+ }
1160
+
1161
+ if (!hasDatasetSpecificKlcOptions && selectBox) {
1020
1162
  const allKLCAreas = Array.from(
1021
1163
  new Set(modularKLCAreas.concat(dichotomousKLCAreas)),
1022
1164
  ).sort((a, b) => a.localeCompare(b));
@@ -1034,20 +1176,60 @@ class HotspotWidget extends React.Component {
1034
1176
  }
1035
1177
  }
1036
1178
  if (selectBox.value === 'default') {
1179
+ hasMultipleLcDatesForSelection = false;
1037
1180
  if (selectBoxLcTime) {
1038
1181
  this.removeOptions(selectBoxLcTime);
1039
1182
  selectBoxLcTime.options.add(
1040
- new Option('Select a region first', 'default', true, true),
1183
+ new Option('Select a year', 'default', true, true),
1041
1184
  );
1042
1185
  selectBoxLcTime.options[0].disabled = true;
1043
1186
  }
1044
1187
  if (selectBoxLccTime) {
1045
1188
  this.removeOptions(selectBoxLccTime);
1046
1189
  selectBoxLccTime.options.add(
1047
- new Option('Select a region first', 'default', true, true),
1190
+ new Option('Select a year', 'default', true, true),
1048
1191
  );
1049
1192
  selectBoxLccTime.options[0].disabled = true;
1050
1193
  }
1194
+
1195
+ if (
1196
+ this.state.selectedArea !== null ||
1197
+ this.state.referenceLcYear !== null ||
1198
+ this.state.lcYear !== null ||
1199
+ this.state.lccYear !== null
1200
+ ) {
1201
+ this.setState({
1202
+ selectedArea: null,
1203
+ referenceLcYear: null,
1204
+ lcYear: null,
1205
+ lccYear: null,
1206
+ });
1207
+ }
1208
+ }
1209
+
1210
+ if (
1211
+ selectBox &&
1212
+ this.state.selectedArea !== null &&
1213
+ Array.from(selectBox.options).some(
1214
+ (option) => option.value === this.state.selectedArea,
1215
+ )
1216
+ ) {
1217
+ selectBox.value = this.state.selectedArea;
1218
+ hasSelectedAreaOption = true;
1219
+ }
1220
+
1221
+ const hasActivePresentLcLayer = activeLayers.some(
1222
+ (layer) =>
1223
+ layer.includes('all_present_lc_a_pol') ||
1224
+ layer.includes('all_present_lc_b_pol') ||
1225
+ layer.includes('lc_filter'),
1226
+ );
1227
+
1228
+ const shouldShowPresentLandCoverDropdown =
1229
+ hasSelectedAreaOption && hasActivePresentLcLayer;
1230
+ this.setPresentLandCoverVisibility(shouldShowPresentLandCoverDropdown);
1231
+ if (this.state.hasMultipleLcDates !== hasMultipleLcDatesForSelection) {
1232
+ this.setState({ hasMultipleLcDates: hasMultipleLcDatesForSelection });
1051
1233
  }
1052
1234
  }
1053
1235
 
@@ -1079,69 +1261,21 @@ class HotspotWidget extends React.Component {
1079
1261
  return;
1080
1262
  }
1081
1263
 
1082
- let rawKeymapInfo = selectedNode.keymap_info;
1083
- let keyMapInfoObj = {};
1084
- if (typeof rawKeymapInfo === 'string') {
1085
- try {
1086
- keyMapInfoObj = JSON.parse(rawKeymapInfo) || {};
1087
- } catch (e) {
1088
- keyMapInfoObj = {};
1089
- }
1090
- } else if (rawKeymapInfo && typeof rawKeymapInfo === 'object') {
1091
- keyMapInfoObj = rawKeymapInfo;
1092
- }
1093
-
1094
- let lccDateList = [];
1095
- let lccDatesByLcYear = {};
1096
-
1097
- if (Array.isArray(keyMapInfoObj.dates)) {
1098
- keyMapInfoObj.dates.forEach((entry) => {
1099
- const lccDate = Number(
1100
- entry && typeof entry === 'object' ? entry?.date : entry,
1101
- );
1102
- const lcDate = Number(
1103
- entry && typeof entry === 'object' ? entry?.lc_date : undefined,
1104
- );
1105
- if (Number.isFinite(lccDate)) {
1106
- lccDateList.push(lccDate);
1107
- }
1108
- if (Number.isFinite(lcDate)) {
1109
- if (!lccDatesByLcYear[lcDate]) {
1110
- lccDatesByLcYear[lcDate] = [];
1111
- }
1112
- if (Number.isFinite(lccDate)) {
1113
- lccDatesByLcYear[lcDate].push(lccDate);
1114
- }
1115
- }
1116
- });
1117
- }
1118
-
1119
- const dynamicYearValues = Object.keys(keyMapInfoObj)
1120
- .filter((key) => /^year\d+$/.test(key))
1121
- .map((key) => Number(keyMapInfoObj[key]))
1122
- .filter((year) => Number.isFinite(year));
1123
- if (dynamicYearValues.length) {
1124
- lccDateList = lccDateList.concat(dynamicYearValues);
1125
- }
1126
-
1127
- if (!lccDateList.length && Number.isFinite(Number(selectedNode.lcc_year))) {
1128
- lccDateList = [Number(selectedNode.lcc_year)];
1129
- }
1130
-
1131
- lccDateList = Array.from(new Set(lccDateList)).sort((a, b) => a - b);
1132
- Object.keys(lccDatesByLcYear).forEach((lcDateKey) => {
1133
- lccDatesByLcYear[lcDateKey] = Array.from(
1134
- new Set(lccDatesByLcYear[lcDateKey]),
1135
- ).sort((a, b) => a - b);
1136
- });
1264
+ const { lccDateList, lcDateList, lccDatesByLcYear } =
1265
+ this.getDateOptionsForNode(selectedNode);
1137
1266
 
1138
- const selectedLcYear = Number(this.state.lcYear);
1139
- const lccOptionsToUse = this.resolveLccDateOptions(
1140
- selectedNode.klc_code,
1141
- selectedLcYear,
1142
- lccDatesByLcYear,
1143
- lccDateList,
1144
- );
1267
+ const selectedLcYear = this.isReferenceSelectionKlcCode(
1268
+ selectedNode?.klc_code,
1269
+ )
1270
+ ? this.getReferenceLcYearSelection(lcDateList)
1271
+ : Number(this.state.lcYear);
1272
+ const lccOptionsToUse = Number.isFinite(Number(selectedLcYear))
1273
+ ? this.getLccDateOptionsFromData(
1274
+ selectedLcYear,
1275
+ lccDatesByLcYear,
1276
+ lccDateList,
1277
+ )
1278
+ : [];
1145
1279
 
1146
1280
  this.removeOptions(selectBoxLccTime);
1147
1281
  selectBoxLccTime.options.add(
@@ -1188,6 +1322,84 @@ class HotspotWidget extends React.Component {
1188
1322
  );
1189
1323
  }
1190
1324
 
1325
+ renderReferenceLandCoverSelection() {
1326
+ const selectedNode = this.getSelectedNodeByArea(this.state.selectedArea);
1327
+ if (
1328
+ !selectedNode ||
1329
+ !this.isReferenceSelectionKlcCode(selectedNode.klc_code)
1330
+ ) {
1331
+ return null;
1332
+ }
1333
+
1334
+ const { lcDateList } = this.getDateOptionsForNode(selectedNode);
1335
+ if (!lcDateList.length) {
1336
+ return null;
1337
+ }
1338
+
1339
+ const selectedReferenceLcYear = this.state.referenceLcYear || 'default';
1340
+
1341
+ return (
1342
+ <div className="measurement-dropdown-container hotspot-reference-selection">
1343
+ <div className="esri-print__form-section-container">
1344
+ <label>
1345
+ Select first the reference land cover date you want to visualize
1346
+ <select
1347
+ id="select-klc-reference-lc-time"
1348
+ className="esri-select"
1349
+ value={selectedReferenceLcYear}
1350
+ onBlur={() => {}}
1351
+ onChange={(e) => {
1352
+ const nextReferenceLcYear = e.target.value;
1353
+ if (nextReferenceLcYear === 'default') {
1354
+ this.setState(
1355
+ {
1356
+ referenceLcYear: null,
1357
+ lcYear: null,
1358
+ lccYear: null,
1359
+ },
1360
+ () => {
1361
+ this.getKLCNames(
1362
+ this.dataJSONNames,
1363
+ this.state.selectedArea,
1364
+ );
1365
+ this.updateLccOptionsForSelectedLc();
1366
+ this.disableButton();
1367
+ },
1368
+ );
1369
+ return;
1370
+ }
1371
+ this.setState(
1372
+ {
1373
+ referenceLcYear: nextReferenceLcYear,
1374
+ lcYear: nextReferenceLcYear,
1375
+ lccYear: null,
1376
+ },
1377
+ () => {
1378
+ this.getKLCNames(
1379
+ this.dataJSONNames,
1380
+ this.state.selectedArea,
1381
+ );
1382
+ this.updateLccOptionsForSelectedLc();
1383
+ this.disableButton();
1384
+ },
1385
+ );
1386
+ }}
1387
+ >
1388
+ <option value="default" disabled>
1389
+ Select a year
1390
+ </option>
1391
+ {lcDateList.map((year) => (
1392
+ <option key={year} value={String(year)}>
1393
+ {year}
1394
+ </option>
1395
+ ))}
1396
+ </select>
1397
+ </label>
1398
+ </div>
1399
+ </div>
1400
+ );
1401
+ }
1402
+
1191
1403
  render() {
1192
1404
  let divs = [
1193
1405
  {
@@ -1270,6 +1482,7 @@ class HotspotWidget extends React.Component {
1270
1482
  onChange={(e) => {
1271
1483
  this.setState({
1272
1484
  selectedArea: e.target.value,
1485
+ referenceLcYear: null,
1273
1486
  lcYear: null,
1274
1487
  lccYear: null,
1275
1488
  });
@@ -1280,6 +1493,7 @@ class HotspotWidget extends React.Component {
1280
1493
  </label>
1281
1494
  </div>
1282
1495
  </div>
1496
+ {this.renderReferenceLandCoverSelection()}
1283
1497
  <div>
1284
1498
  {divs.map((div, i) => (
1285
1499
  <div key={i} className={div.className}>
@@ -1361,7 +1575,12 @@ class HotspotWidget extends React.Component {
1361
1575
  this.lccYear = null;
1362
1576
  this.selectedArea = null;
1363
1577
  if (this._isMounted) {
1364
- this.setState({ lcYear: null, lccYear: null, selectedArea: null });
1578
+ this.setState({
1579
+ lcYear: null,
1580
+ lccYear: null,
1581
+ selectedArea: null,
1582
+ referenceLcYear: null,
1583
+ });
1365
1584
  }
1366
1585
  shouldUpdate = true;
1367
1586
  }
@@ -1398,9 +1617,7 @@ class HotspotWidget extends React.Component {
1398
1617
  return '';
1399
1618
  }
1400
1619
  return Object.keys(activeLayers)
1401
- .filter(
1402
- (key) => key.includes('all_present_lc_') || key.includes('all_lcc_'),
1403
- )
1620
+ .filter((key) => this.isHotspotLayerKey(key))
1404
1621
  .sort()
1405
1622
  .join('|');
1406
1623
  }
@@ -1413,17 +1630,16 @@ class HotspotWidget extends React.Component {
1413
1630
  this.props.hotspotData,
1414
1631
  );
1415
1632
 
1416
- if (
1417
- prevHotspotLayerSignature !== nextHotspotLayerSignature &&
1418
- (this.state.selectedArea !== null ||
1419
- this.state.lcYear !== null ||
1420
- this.state.lccYear !== null)
1421
- ) {
1422
- this.setState({
1423
- selectedArea: null,
1424
- lcYear: null,
1425
- lccYear: null,
1426
- });
1633
+ if (prevHotspotLayerSignature !== nextHotspotLayerSignature) {
1634
+ this.clearHotspotLayersFromMap();
1635
+ this.resetHotspotViewState();
1636
+ const newHotspotData = {
1637
+ ...(this.props.hotspotData || {}),
1638
+ filteredLayers: {},
1639
+ filteredLayersData: {},
1640
+ };
1641
+ this.props.hotspotDataHandler(newHotspotData);
1642
+ this.resetHotspotWidgetFilters();
1427
1643
  return;
1428
1644
  }
1429
1645
 
@@ -1437,6 +1653,9 @@ class HotspotWidget extends React.Component {
1437
1653
  if (prevState.lcYear !== this.state.lcYear) {
1438
1654
  this.disableButton();
1439
1655
  }
1656
+ if (prevState.referenceLcYear !== this.state.referenceLcYear) {
1657
+ this.disableButton();
1658
+ }
1440
1659
  }
1441
1660
  }
1442
1661
  export default HotspotWidget;
@@ -7358,33 +7358,78 @@ class MenuWidget extends React.Component {
7358
7358
  this.hideOnClickOutsideOpacity();
7359
7359
  }
7360
7360
 
7361
+ getHotspotFilterLayerId(layerId, options = {}) {
7362
+ const { requireActive = false } = options;
7363
+ if (!layerId || typeof layerId !== 'string') {
7364
+ return null;
7365
+ }
7366
+ let filterLayerId = null;
7367
+ if (layerId === 'lcc_filter' || layerId.includes('all_lcc')) {
7368
+ filterLayerId = 'lcc_filter';
7369
+ } else if (layerId === 'lc_filter' || layerId.includes('all_present')) {
7370
+ filterLayerId = 'lc_filter';
7371
+ } else if (layerId === 'klc_filter' || layerId.includes('cop_klc')) {
7372
+ filterLayerId = 'klc_filter';
7373
+ } else if (layerId === 'pa_filter' || layerId.includes('protected_areas')) {
7374
+ filterLayerId = 'pa_filter';
7375
+ }
7376
+
7377
+ if (!filterLayerId) {
7378
+ return null;
7379
+ }
7380
+
7381
+ if (!requireActive || layerId === filterLayerId) {
7382
+ return filterLayerId;
7383
+ }
7384
+
7385
+ const hotspotFilteredLayers =
7386
+ this.props.hotspotData &&
7387
+ this.props.hotspotData.filteredLayers &&
7388
+ typeof this.props.hotspotData.filteredLayers === 'object'
7389
+ ? this.props.hotspotData.filteredLayers
7390
+ : {};
7391
+ const hasFilteredEntry = Object.prototype.hasOwnProperty.call(
7392
+ hotspotFilteredLayers,
7393
+ filterLayerId,
7394
+ );
7395
+ const mapLayer =
7396
+ this.map && typeof this.map.findLayerById === 'function'
7397
+ ? this.map.findLayerById(filterLayerId)
7398
+ : null;
7399
+ const hasVisibleFilterLayer =
7400
+ (this.layers[filterLayerId] && this.layers[filterLayerId].visible) ||
7401
+ (mapLayer && mapLayer.visible);
7402
+
7403
+ if (hasFilteredEntry && (mapLayer || hasVisibleFilterLayer)) {
7404
+ return filterLayerId;
7405
+ }
7406
+
7407
+ return null;
7408
+ }
7409
+
7361
7410
  setOpacity() {
7362
7411
  let layer = document.querySelector('.opacity-slider input').dataset.layer;
7363
7412
  let value = document.querySelector('.opacity-panel input').value;
7364
7413
 
7365
- if (this.layers['lcc_filter'] && layer.includes('all_lcc')) {
7366
- this.layers['lcc_filter'].opacity = value / 100;
7367
- this.saveOpacity(this.layers['lcc_filter'], value / 100);
7368
- } else if (this.layers['lc_filter'] && layer.includes('all_present')) {
7369
- this.layers['lc_filter'].opacity = value / 100;
7370
- this.saveOpacity(this.layers['lc_filter'], value / 100);
7371
- } else if (this.layers['klc_filter'] && layer.includes('cop_klc')) {
7372
- this.layers['klc_filter'].opacity = value / 100;
7373
- this.saveOpacity(this.layers['klc_filter'], value / 100);
7374
- } else if (this.layers['pa_filter'] && layer.includes('protected_areas')) {
7375
- this.layers['pa_filter'].opacity = value / 100;
7376
- this.saveOpacity(this.layers['pa_filter'], value / 100);
7377
- }
7378
- this.layers[layer].opacity = value / 100;
7379
- this.saveOpacity(layer, value / 100);
7380
- if (
7381
- this.map.findLayerById(layer) &&
7382
- this.map.findLayerById(layer) !== null &&
7383
- (this.map.findLayerById(layer).opacity ||
7384
- this.map.findLayerById(layer).opacity === 0)
7385
- ) {
7386
- this.map.findLayerById(layer).opacity = value / 100;
7414
+ const filterLayerId = this.getHotspotFilterLayerId(layer, {
7415
+ requireActive: true,
7416
+ });
7417
+ const targetLayerId =
7418
+ filterLayerId && this.layers[filterLayerId] ? filterLayerId : layer;
7419
+ if (!this.layers[targetLayerId]) {
7420
+ return;
7387
7421
  }
7422
+ this.layers[targetLayerId].opacity = value / 100;
7423
+ this.saveOpacity(targetLayerId, value / 100);
7424
+
7425
+ const mapLayer =
7426
+ this.map && typeof this.map.findLayerById === 'function'
7427
+ ? this.map.findLayerById(targetLayerId)
7428
+ : null;
7429
+ if (mapLayer && (mapLayer.opacity || mapLayer.opacity === 0)) {
7430
+ mapLayer.opacity = value / 100;
7431
+ }
7432
+
7388
7433
  document.querySelector(
7389
7434
  '.active-layer[layer-id="' + layer + '"] .active-layer-opacity',
7390
7435
  ).dataset.opacity = value;
@@ -7589,46 +7634,31 @@ class MenuWidget extends React.Component {
7589
7634
  if (!isUserServiceLayer) {
7590
7635
  this.findCheckedDataset(elem);
7591
7636
  }
7637
+
7638
+ const filterLayerId = this.getHotspotFilterLayerId(elem.id, {
7639
+ requireActive: true,
7640
+ });
7641
+ const targetLayerId =
7642
+ filterLayerId && this.layers[filterLayerId] ? filterLayerId : elem.id;
7643
+
7644
+ if (!this.layers[targetLayerId]) {
7645
+ return;
7646
+ }
7647
+
7592
7648
  if (
7593
7649
  !this.visibleLayers[elem.id] ||
7594
7650
  this.visibleLayers[elem.id][1] === 'eye'
7595
7651
  ) {
7596
- this.layers[elem.id].visible = false;
7652
+ this.layers[targetLayerId].visible = false;
7597
7653
  this.visibleLayers[elem.id] = ['fas', 'eye-slash'];
7598
- if (this.layers['lcc_filter'] && elem.id.includes('all_lcc')) {
7599
- this.map.remove(this.layers['lcc_filter']);
7600
- this.layers['lcc_filter'].visible = false;
7601
- } else if (this.layers['lc_filter'] && elem.id.includes('all_present')) {
7602
- this.map.remove(this.layers['lc_filter']);
7603
- this.layers['lc_filter'].visible = false;
7604
- } else if (this.layers['klc_filter'] && elem.id.includes('cop_klc')) {
7605
- this.map.remove(this.layers['klc_filter']);
7606
- this.layers['klc_filter'].visible = false;
7607
- } else if (
7608
- this.layers['pa_filter'] &&
7609
- elem.id.includes('protected_areas')
7610
- ) {
7611
- this.map.remove(this.layers['pa_filter']);
7612
- this.layers['pa_filter'].visible = false;
7654
+ if (targetLayerId !== elem.id && this.layers[elem.id]) {
7655
+ this.layers[elem.id].visible = false;
7613
7656
  }
7657
+ this.map.remove(this.layers[targetLayerId]);
7614
7658
  } else {
7615
- if (this.layers['lcc_filter'] && elem.id.includes('all_lcc')) {
7616
- this.map.add(this.layers['lcc_filter']);
7617
- this.layers['lcc_filter'].visible = true;
7618
- } else if (this.layers['lc_filter'] && elem.id.includes('all_present')) {
7619
- this.map.add(this.layers['lc_filter']);
7620
- this.layers['lc_filter'].visible = true;
7621
- } else if (this.layers['klc_filter'] && elem.id.includes('cop_klc')) {
7622
- this.map.add(this.layers['klc_filter']);
7623
- this.layers['klc_filter'].visible = true;
7624
- } else if (
7625
- this.layers['pa_filter'] &&
7626
- elem.id.includes('protected_areas')
7627
- ) {
7628
- this.map.add(this.layers['pa_filter']);
7629
- this.layers['pa_filter'].visible = true;
7630
- } else {
7631
- this.map.add(this.layers[elem.id]);
7659
+ this.map.add(this.layers[targetLayerId]);
7660
+ this.layers[targetLayerId].visible = true;
7661
+ if (targetLayerId !== elem.id && this.layers[elem.id]) {
7632
7662
  this.layers[elem.id].visible = true;
7633
7663
  }
7634
7664
  this.visibleLayers[elem.id] = ['fas', 'eye'];
@@ -7883,6 +7913,26 @@ class MenuWidget extends React.Component {
7883
7913
  * @param {*} id id from elem
7884
7914
  */
7885
7915
  deleteCrossEvent(elem) {
7916
+ if (
7917
+ elem.id === 'lcc_filter' ||
7918
+ elem.id === 'lc_filter' ||
7919
+ elem.id === 'klc_filter' ||
7920
+ elem.id === 'pa_filter'
7921
+ ) {
7922
+ this.deleteFilteredLayer(elem.id);
7923
+ delete this.activeLayersJSON[elem.id];
7924
+ if (this.visibleLayers && this.visibleLayers[elem.id]) {
7925
+ delete this.visibleLayers[elem.id];
7926
+ }
7927
+ if (this.timeLayers && this.timeLayers[elem.id]) {
7928
+ delete this.timeLayers[elem.id];
7929
+ }
7930
+ this.layersReorder();
7931
+ this.saveLayerOrder();
7932
+ this.checkInfoWidget();
7933
+ this.setState({});
7934
+ return;
7935
+ }
7886
7936
  elem.checked = false;
7887
7937
  this.toggleLayer(elem);
7888
7938
  delete this.activeLayersJSON[elem.id];
@@ -8018,16 +8068,13 @@ class MenuWidget extends React.Component {
8018
8068
 
8019
8069
  deleteFilteredLayer(layer) {
8020
8070
  if (!layer || !this.props || !this.props.map) return;
8021
- if (
8022
- !(
8023
- layer.includes('all_lcc') ||
8024
- layer.includes('all_present') ||
8025
- layer.includes('cop_klc') ||
8026
- layer.includes('protected_areas')
8027
- )
8028
- )
8071
+ const filterLayerId =
8072
+ this.getHotspotFilterLayerId(layer, {
8073
+ requireActive: true,
8074
+ }) || this.getHotspotFilterLayerId(layer);
8075
+ if (!filterLayerId) {
8029
8076
  return;
8030
- let filterLayer;
8077
+ }
8031
8078
  let updatedHotspotData = this.props.hotspotData || {};
8032
8079
  let updatedFilteredLayers =
8033
8080
  updatedHotspotData &&
@@ -8035,60 +8082,19 @@ class MenuWidget extends React.Component {
8035
8082
  typeof updatedHotspotData['filteredLayers'] === 'object'
8036
8083
  ? updatedHotspotData['filteredLayers']
8037
8084
  : {};
8038
- if (this.layers['lcc_filter'] && layer.includes('all_lcc')) {
8039
- this.layers['lcc_filter'].visible = false;
8040
- filterLayer = this.props.map.findLayerById('lcc_filter');
8041
- if (filterLayer !== undefined) {
8042
- filterLayer.clear();
8043
- filterLayer.destroy();
8044
- this.props.map.remove(filterLayer);
8045
- }
8046
- delete updatedFilteredLayers['lcc_filter'];
8047
- delete this.layers['lcc_filter'];
8048
- } else if (this.layers['lc_filter'] && layer.includes('all_present_lc')) {
8049
- this.layers['lc_filter'].visible = false;
8050
- filterLayer = this.props.map.findLayerById('lc_filter');
8051
- if (filterLayer !== undefined) {
8052
- filterLayer.clear();
8053
- filterLayer.destroy();
8054
- this.props.map.remove(filterLayer);
8055
- }
8056
- delete updatedFilteredLayers['lc_filter'];
8057
- delete this.layers['lc_filter'];
8058
- } else if (
8059
- this.layers['klc_filter'] !== undefined &&
8060
- layer.includes('cop_klc')
8061
- ) {
8062
- this.layers['klc_filter'].visible = false;
8063
- if (this.layers[layer]) {
8064
- this.layers[layer].visible = false;
8065
- }
8066
- filterLayer = this.props.map.findLayerById('klc_filter');
8067
- if (filterLayer !== undefined) {
8068
- // temp = filterLayer;
8069
- filterLayer.clear();
8070
- filterLayer.destroy();
8071
- this.props.map.remove(filterLayer);
8072
- }
8073
- delete updatedFilteredLayers['klc_filter'];
8074
- //delete this.layers['klc_filter'];
8075
- } else if (
8076
- this.layers['pa_filter'] !== undefined &&
8077
- layer.includes('protected_areas')
8078
- ) {
8079
- this.layers['pa_filter'].visible = false;
8080
- if (this.layers[layer]) {
8081
- this.layers[layer].visible = false;
8082
- }
8083
- filterLayer = this.props.map.findLayerById('pa_filter');
8084
- if (filterLayer !== undefined) {
8085
- // temp = filterLayer;
8086
- filterLayer.clear();
8087
- filterLayer.destroy();
8088
- this.props.map.remove(filterLayer);
8085
+ if (this.layers[filterLayerId]) {
8086
+ this.layers[filterLayerId].visible = false;
8087
+ this.props.map.remove(this.layers[filterLayerId]);
8088
+ const mapFilterLayer = this.props.map.findLayerById(filterLayerId);
8089
+ if (mapFilterLayer) {
8090
+ this.props.map.remove(mapFilterLayer);
8089
8091
  }
8090
- delete updatedFilteredLayers['pa_filter'];
8091
8092
  }
8093
+ if (this.layers[layer]) {
8094
+ this.layers[layer].visible = false;
8095
+ }
8096
+ delete updatedFilteredLayers[filterLayerId];
8097
+ delete this.layers[filterLayerId];
8092
8098
  this.props.mapLayersHandler(this.layers);
8093
8099
  if (this.props.hotspotDataHandler) {
8094
8100
  updatedHotspotData['filteredLayers'] = updatedFilteredLayers;
@@ -1975,6 +1975,17 @@ div.map-container.popup-block {
1975
1975
  cursor: not-allowed;
1976
1976
  }
1977
1977
 
1978
+ .hotspot-reference-selection {
1979
+ padding: 8px;
1980
+ margin-top: 10px;
1981
+ margin-bottom: 10px;
1982
+ background: rgba(160, 177, 40, 0.15);
1983
+ }
1984
+
1985
+ .hotspot-reference-selection .esri-select {
1986
+ margin-top: 8px;
1987
+ }
1988
+
1978
1989
  /*.hotspot-container .esri-select{
1979
1990
  font-family:Helvetica, sans-serif;
1980
1991
  font-size:20px;