@eeacms/volto-arcgis-block 0.1.13 → 0.1.17
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 +61 -0
- package/Jenkinsfile +28 -5
- package/package.json +6 -2
- package/src/components/MapViewer/AreaWidget.jsx +88 -37
- package/src/components/MapViewer/LegendWidget.jsx +2 -0
- package/src/components/MapViewer/MapViewer.jsx +8 -0
- package/src/components/MapViewer/MenuWidget.jsx +498 -108
- package/src/components/MapViewer/TimesliderWidget.jsx +81 -0
- package/src/components/MapViewer/css/ArcgisMap.css +50 -9
- package/src/components/UseCasesMapViewer/InfoWidget.jsx +30 -32
- package/src/components/UseCasesMapViewer/LayerControl.jsx +58 -23
- package/src/components/UseCasesMapViewer/LegendWidget.jsx +122 -0
- package/src/components/UseCasesMapViewer/NavigationControl.jsx +2 -2
- package/src/components/UseCasesMapViewer/UseCasesMapViewer.jsx +39 -51
- package/src/components/UseCasesMapViewer/config.js +15 -1
- package/src/components/UseCasesMapViewer/css/ArcgisMap.css +26 -0
- package/src/components/UseCasesMapViewer/map.css +0 -6
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React, { createRef } from 'react';
|
|
2
|
+
import { loadModules } from 'esri-loader';
|
|
3
|
+
var TimeSlider;
|
|
4
|
+
|
|
5
|
+
class TimesliderWidget extends React.Component {
|
|
6
|
+
/**
|
|
7
|
+
* Creator of the TimeSlider widget class
|
|
8
|
+
* @param {*} props
|
|
9
|
+
*/
|
|
10
|
+
constructor(props) {
|
|
11
|
+
super(props);
|
|
12
|
+
//We create a reference to a DOM element to be mounted
|
|
13
|
+
this.container = createRef();
|
|
14
|
+
//Initially, we set the state of the component to
|
|
15
|
+
//not be showing the basemap panel
|
|
16
|
+
this.state = { showMapMenu: false };
|
|
17
|
+
this.map = this.props.map;
|
|
18
|
+
this.layer = this.props.layer;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
loader() {
|
|
22
|
+
return loadModules([
|
|
23
|
+
'esri/widgets/TimeSlider',
|
|
24
|
+
'esri/layers/WMSLayer',
|
|
25
|
+
]).then(([_TimeSlider]) => {
|
|
26
|
+
[TimeSlider] = [_TimeSlider];
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* This method is executed after the rener method is executed
|
|
32
|
+
*/
|
|
33
|
+
async componentDidMount() {
|
|
34
|
+
await this.loader();
|
|
35
|
+
this.TimesliderWidget = new TimeSlider({
|
|
36
|
+
view: this.props.view,
|
|
37
|
+
container: document.querySelector('.timeslider-panel'),
|
|
38
|
+
timeVisible: true,
|
|
39
|
+
mode: this.props.download ? 'time-window' : 'instant',
|
|
40
|
+
loop: false,
|
|
41
|
+
values: this.props.time.start
|
|
42
|
+
? this.props.download
|
|
43
|
+
? [new Date(this.props.time.start), new Date(this.props.time.end)]
|
|
44
|
+
: [new Date(this.props.time.start)]
|
|
45
|
+
: null,
|
|
46
|
+
});
|
|
47
|
+
this.props.view.ui.add(this.container.current, 'bottom-right');
|
|
48
|
+
this.container.current.style.display = 'block';
|
|
49
|
+
|
|
50
|
+
this.props.view.whenLayerView(this.layer).then((lv) => {
|
|
51
|
+
this.TimesliderWidget.fullTimeExtent = this.layer.timeInfo.fullTimeExtent;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.TimesliderWidget.watch('timeExtent', (timeExtent) => {
|
|
55
|
+
let start = new Date(timeExtent.start).getTime();
|
|
56
|
+
let end = new Date(timeExtent.end).getTime();
|
|
57
|
+
this.props.time.elem.setAttribute('time-start', start);
|
|
58
|
+
this.props.time.elem.setAttribute('time-end', end);
|
|
59
|
+
if (this.props.download) {
|
|
60
|
+
this.props.time.dataset.setAttribute('time-start', start);
|
|
61
|
+
this.props.time.dataset.setAttribute('time-end', end);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* This method renders the component
|
|
68
|
+
* @returns jsx
|
|
69
|
+
*/
|
|
70
|
+
render() {
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
<div ref={this.container} className="timeslider-container">
|
|
74
|
+
<div className="timeslider-panel"></div>
|
|
75
|
+
</div>
|
|
76
|
+
</>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default TimesliderWidget;
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
.esri-component.esri-zoom.esri-widget {
|
|
41
|
-
margin-bottom: 0;
|
|
42
41
|
background: none;
|
|
43
42
|
box-shadow: none;
|
|
44
43
|
}
|
|
@@ -83,6 +82,11 @@
|
|
|
83
82
|
box-shadow: none !important;
|
|
84
83
|
}
|
|
85
84
|
|
|
85
|
+
.basemap-panel.esri-basemap-gallery {
|
|
86
|
+
width: 300px;
|
|
87
|
+
max-height: 260px;
|
|
88
|
+
}
|
|
89
|
+
|
|
86
90
|
.esri-basemap-gallery {
|
|
87
91
|
display: none;
|
|
88
92
|
margin: 0 !important;
|
|
@@ -92,10 +96,6 @@
|
|
|
92
96
|
margin: 0;
|
|
93
97
|
}
|
|
94
98
|
|
|
95
|
-
.esri-view-height-small .esri-ui-corner .esri-widget--panel-height-only {
|
|
96
|
-
max-height: 260px;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
99
|
/* Measure */
|
|
100
100
|
.measurement-container {
|
|
101
101
|
display: flex;
|
|
@@ -104,12 +104,13 @@
|
|
|
104
104
|
|
|
105
105
|
.measurement-container .measurement-area.esri-measurement {
|
|
106
106
|
display: block;
|
|
107
|
-
width: 225px;
|
|
108
107
|
flex-direction: column;
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
.measurement-panel {
|
|
112
111
|
display: none;
|
|
112
|
+
width: 300px;
|
|
113
|
+
max-height: 260px;
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
.measurement-buttons {
|
|
@@ -192,7 +193,8 @@
|
|
|
192
193
|
|
|
193
194
|
.area-panel {
|
|
194
195
|
display: none;
|
|
195
|
-
width:
|
|
196
|
+
width: 300px;
|
|
197
|
+
max-height: 260px;
|
|
196
198
|
padding: 1rem;
|
|
197
199
|
background-color: white;
|
|
198
200
|
font-size: 1rem;
|
|
@@ -210,14 +212,17 @@
|
|
|
210
212
|
|
|
211
213
|
/* Left menu */
|
|
212
214
|
.map-menu {
|
|
215
|
+
position: relative;
|
|
213
216
|
display: none;
|
|
214
217
|
width: 450px;
|
|
215
218
|
font-size: 1rem;
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
.map-menu.tab-container .tab {
|
|
219
|
-
display:
|
|
222
|
+
display: flex !important;
|
|
220
223
|
width: 50%;
|
|
224
|
+
align-items: center;
|
|
225
|
+
justify-content: center;
|
|
221
226
|
padding: 1rem;
|
|
222
227
|
border-bottom: solid 4px white;
|
|
223
228
|
margin: 0;
|
|
@@ -226,6 +231,7 @@
|
|
|
226
231
|
cursor: pointer;
|
|
227
232
|
font-weight: bold;
|
|
228
233
|
text-align: center;
|
|
234
|
+
white-space: normal;
|
|
229
235
|
}
|
|
230
236
|
|
|
231
237
|
.map-menu.tab-container .tab-selected {
|
|
@@ -234,6 +240,9 @@
|
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
.map-menu.tab-container .tabs {
|
|
243
|
+
display: flex;
|
|
244
|
+
align-items: stretch;
|
|
245
|
+
justify-content: space-around;
|
|
237
246
|
border-bottom: solid 1px #dadada;
|
|
238
247
|
background-color: white;
|
|
239
248
|
white-space: nowrap;
|
|
@@ -294,6 +303,14 @@
|
|
|
294
303
|
}
|
|
295
304
|
}
|
|
296
305
|
|
|
306
|
+
.map-menu .login-block {
|
|
307
|
+
width: 100%;
|
|
308
|
+
margin: 0;
|
|
309
|
+
background: none;
|
|
310
|
+
float: none;
|
|
311
|
+
font-size: 0.85rem;
|
|
312
|
+
}
|
|
313
|
+
|
|
297
314
|
.map-menu.tab-container .panel-selected {
|
|
298
315
|
display: block;
|
|
299
316
|
}
|
|
@@ -450,6 +467,12 @@
|
|
|
450
467
|
cursor: move;
|
|
451
468
|
}
|
|
452
469
|
|
|
470
|
+
.locked {
|
|
471
|
+
cursor: auto;
|
|
472
|
+
opacity: 0.3;
|
|
473
|
+
pointer-events: none;
|
|
474
|
+
}
|
|
475
|
+
|
|
453
476
|
.active-layer-options {
|
|
454
477
|
white-space: nowrap;
|
|
455
478
|
}
|
|
@@ -519,7 +542,7 @@
|
|
|
519
542
|
.map-download-buttons {
|
|
520
543
|
display: flex;
|
|
521
544
|
justify-content: space-between;
|
|
522
|
-
margin
|
|
545
|
+
margin: 0 1rem;
|
|
523
546
|
}
|
|
524
547
|
|
|
525
548
|
.map-download-block .ccl-form-group:not(:first-of-type) {
|
|
@@ -531,6 +554,15 @@
|
|
|
531
554
|
height: 100%;
|
|
532
555
|
}
|
|
533
556
|
|
|
557
|
+
.ui.floating.message {
|
|
558
|
+
position: absolute;
|
|
559
|
+
z-index: 1;
|
|
560
|
+
left: 0;
|
|
561
|
+
width: 100%;
|
|
562
|
+
margin: 0;
|
|
563
|
+
transform: translate(0, 4rem);
|
|
564
|
+
}
|
|
565
|
+
|
|
534
566
|
/* Legend*/
|
|
535
567
|
.legend-container {
|
|
536
568
|
display: flex;
|
|
@@ -545,3 +577,12 @@
|
|
|
545
577
|
.legend-panel.esri-legend {
|
|
546
578
|
overflow: auto;
|
|
547
579
|
}
|
|
580
|
+
|
|
581
|
+
/* Modal */
|
|
582
|
+
.ui.modal {
|
|
583
|
+
margin: 0 !important;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.ui.modal p {
|
|
587
|
+
font-size: 1rem;
|
|
588
|
+
}
|
|
@@ -23,6 +23,11 @@ class InfoWidget extends React.Component {
|
|
|
23
23
|
* @returns lateralMenu DOM
|
|
24
24
|
*/
|
|
25
25
|
showUseCase(UseCase) {
|
|
26
|
+
let responsibleOrganizationOrPerson = UseCase.Responsible_organisation
|
|
27
|
+
? UseCase.Responsible_organisation
|
|
28
|
+
: UseCase.Contact_person_name_
|
|
29
|
+
? UseCase.Contact_person_name_
|
|
30
|
+
: '';
|
|
26
31
|
return (
|
|
27
32
|
<>
|
|
28
33
|
<div className="use-cases-products-title">Use case detail</div>
|
|
@@ -37,12 +42,7 @@ class InfoWidget extends React.Component {
|
|
|
37
42
|
></span>
|
|
38
43
|
</div>
|
|
39
44
|
<div className="use-case-detail-image">
|
|
40
|
-
<img
|
|
41
|
-
src={
|
|
42
|
-
'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg'
|
|
43
|
-
}
|
|
44
|
-
alt="Placeholder"
|
|
45
|
-
/>
|
|
45
|
+
<img src={UseCase.Link_to_image} alt="Use Case" />
|
|
46
46
|
</div>
|
|
47
47
|
<div className="use-case-detail-content">
|
|
48
48
|
<div className="use-case-detail-product">
|
|
@@ -55,13 +55,14 @@ class InfoWidget extends React.Component {
|
|
|
55
55
|
<span>{UseCase.Use_case_topics}</span>
|
|
56
56
|
<span>{UseCase.Use_case_submitting_production_year}</span>
|
|
57
57
|
<span>{UseCase.Spatial_coverage}</span>
|
|
58
|
+
<span>{responsibleOrganizationOrPerson}</span>
|
|
58
59
|
</div>
|
|
59
60
|
<div className="use-case-detail-description">
|
|
60
61
|
<p>{UseCase.Use_case_summary}</p>
|
|
61
62
|
{UseCase.Links_to_web_sites && (
|
|
62
63
|
<p>
|
|
63
|
-
For further information
|
|
64
|
-
<a href={UseCase.Links_to_web_sites}>here</a>.
|
|
64
|
+
For further information
|
|
65
|
+
<a href={UseCase.Links_to_web_sites.split(' ')[0]}> here</a>.
|
|
65
66
|
</p>
|
|
66
67
|
)}
|
|
67
68
|
</div>
|
|
@@ -77,7 +78,12 @@ class InfoWidget extends React.Component {
|
|
|
77
78
|
* @returns useCasesRegion
|
|
78
79
|
*/
|
|
79
80
|
getDataBrief(data) {
|
|
80
|
-
|
|
81
|
+
let children = data.map((val) => {
|
|
82
|
+
let responsibleOrganizationOrPerson = val.Responsible_organisation
|
|
83
|
+
? val.Responsible_organisation
|
|
84
|
+
: val.Contact_person_name_
|
|
85
|
+
? val.Contact_person_name_
|
|
86
|
+
: '';
|
|
81
87
|
return (
|
|
82
88
|
<>
|
|
83
89
|
<div
|
|
@@ -98,6 +104,7 @@ class InfoWidget extends React.Component {
|
|
|
98
104
|
<span>{val.Use_case_topics}</span>
|
|
99
105
|
<span>{val.Use_case_submitting_production_year}</span>
|
|
100
106
|
<span>{val.Spatial_coverage}</span>
|
|
107
|
+
<span>{responsibleOrganizationOrPerson}</span>
|
|
101
108
|
</div>
|
|
102
109
|
</div>
|
|
103
110
|
</>
|
|
@@ -113,7 +120,7 @@ class InfoWidget extends React.Component {
|
|
|
113
120
|
* @returns useCasesDOM
|
|
114
121
|
*/
|
|
115
122
|
showBrief(selectedRegion) {
|
|
116
|
-
|
|
123
|
+
let regionFeatures = [];
|
|
117
124
|
if (mapViewer.state.useCaseLevel === 2) {
|
|
118
125
|
for (let feature in this.features) {
|
|
119
126
|
if (this.features[feature].attributes.Region === selectedRegion) {
|
|
@@ -183,8 +190,8 @@ class InfoWidget extends React.Component {
|
|
|
183
190
|
* Transfrom raw data to ordered data by Service products
|
|
184
191
|
*/
|
|
185
192
|
proccessDataSummary() {
|
|
186
|
-
|
|
187
|
-
|
|
193
|
+
let serviceProducts = this.getDifferentproductUsed(this.features);
|
|
194
|
+
let elements = [];
|
|
188
195
|
|
|
189
196
|
for (let serviceProduct in serviceProducts) {
|
|
190
197
|
processedData[serviceProducts[serviceProduct]] = [];
|
|
@@ -208,7 +215,7 @@ class InfoWidget extends React.Component {
|
|
|
208
215
|
* @returns lateralMenuDOM
|
|
209
216
|
*/
|
|
210
217
|
getDataSummary(data, Copernicus_Land_Monitoring_Service_products_used) {
|
|
211
|
-
|
|
218
|
+
let children = this.getDataBrief(data);
|
|
212
219
|
|
|
213
220
|
return (
|
|
214
221
|
<>
|
|
@@ -247,7 +254,7 @@ class InfoWidget extends React.Component {
|
|
|
247
254
|
*/
|
|
248
255
|
setDOMSummary() {
|
|
249
256
|
this.proccessDataSummary();
|
|
250
|
-
|
|
257
|
+
let DOMElements = [];
|
|
251
258
|
for (let product_use_name in processedData)
|
|
252
259
|
DOMElements.push(
|
|
253
260
|
this.getDataSummary(processedData[product_use_name], product_use_name),
|
|
@@ -326,17 +333,6 @@ class InfoWidget extends React.Component {
|
|
|
326
333
|
}
|
|
327
334
|
}
|
|
328
335
|
|
|
329
|
-
/**
|
|
330
|
-
* It highlights the information displayed for a use case on the infoWidget.
|
|
331
|
-
* */
|
|
332
|
-
highligtInfo() {}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Highlights the point on the map corresponding to the use case
|
|
336
|
-
* @param {*} coords
|
|
337
|
-
*/
|
|
338
|
-
highligtPoint(coords) {}
|
|
339
|
-
|
|
340
336
|
/**
|
|
341
337
|
* This method will return the corresponding lateral menu depending on layers.
|
|
342
338
|
* @returns HTML
|
|
@@ -350,10 +346,10 @@ class InfoWidget extends React.Component {
|
|
|
350
346
|
case 3:
|
|
351
347
|
return this.showBrief(mapViewer.state.selectedUseCases);
|
|
352
348
|
case 4:
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
349
|
+
let title = mapViewer.state.selectedUseCase.Use_case_title;
|
|
350
|
+
let bbox = mapViewer.state.selectedUseCase.BBOX;
|
|
351
|
+
let region = mapViewer.state.selectedUseCase.Region;
|
|
352
|
+
let country = mapViewer.state.selectedUseCase.Spatial_coverage;
|
|
357
353
|
navigationControl.navigateToLocation(
|
|
358
354
|
bbox,
|
|
359
355
|
title,
|
|
@@ -361,9 +357,11 @@ class InfoWidget extends React.Component {
|
|
|
361
357
|
country,
|
|
362
358
|
layerSpatial,
|
|
363
359
|
);
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
360
|
+
try {
|
|
361
|
+
document
|
|
362
|
+
.querySelector('.use-cases-products-list')
|
|
363
|
+
.scrollTo({ top: 0, behavior: 'smooth' });
|
|
364
|
+
} catch {}
|
|
367
365
|
return this.showUseCase(mapViewer.state.selectedUseCase);
|
|
368
366
|
default:
|
|
369
367
|
return 0;
|
|
@@ -3,6 +3,8 @@ class LayerControl {
|
|
|
3
3
|
constructor(props) {
|
|
4
4
|
this.map = props.map;
|
|
5
5
|
this.view = props.view;
|
|
6
|
+
this.worldDimensions = props.worldDimensions;
|
|
7
|
+
this.maxZoom = props.maxZoom;
|
|
6
8
|
mapViewer = props.mapViewer;
|
|
7
9
|
FeatureLayer = props.FeatureLayer;
|
|
8
10
|
Extent = props.Extent;
|
|
@@ -14,7 +16,7 @@ class LayerControl {
|
|
|
14
16
|
* @returns FeatureLayer
|
|
15
17
|
*/
|
|
16
18
|
createLayer(layerInfo) {
|
|
17
|
-
|
|
19
|
+
let newLayer = new FeatureLayer({
|
|
18
20
|
url: layerInfo.url,
|
|
19
21
|
id: layerInfo.id,
|
|
20
22
|
outFields: ['*'],
|
|
@@ -37,7 +39,7 @@ class LayerControl {
|
|
|
37
39
|
* @param {String} id
|
|
38
40
|
*/
|
|
39
41
|
showLayer(id) {
|
|
40
|
-
|
|
42
|
+
let items = this.map.layers.items;
|
|
41
43
|
for (let layer in items)
|
|
42
44
|
items[layer].id === id && (items[layer].visible = true);
|
|
43
45
|
}
|
|
@@ -47,7 +49,7 @@ class LayerControl {
|
|
|
47
49
|
* @param {String} id
|
|
48
50
|
*/
|
|
49
51
|
hideLayer(id) {
|
|
50
|
-
|
|
52
|
+
let items = this.map.layers.items;
|
|
51
53
|
for (let layer in items) {
|
|
52
54
|
items[layer].id === id && (items[layer].visible = false);
|
|
53
55
|
}
|
|
@@ -58,7 +60,7 @@ class LayerControl {
|
|
|
58
60
|
* @param {String} id
|
|
59
61
|
*/
|
|
60
62
|
removeLayer(id) {
|
|
61
|
-
|
|
63
|
+
let items = this.map.layers.items;
|
|
62
64
|
for (let layer in items)
|
|
63
65
|
items[layer].id === id && this.map.remove(items[layer]);
|
|
64
66
|
}
|
|
@@ -68,39 +70,45 @@ class LayerControl {
|
|
|
68
70
|
* @param {Array} boundingBox
|
|
69
71
|
*/
|
|
70
72
|
zoomToExtent(boundingBox) {
|
|
71
|
-
|
|
73
|
+
let newExtent = new Extent(
|
|
72
74
|
boundingBox[0],
|
|
73
75
|
boundingBox[1],
|
|
74
76
|
boundingBox[2],
|
|
75
77
|
boundingBox[3],
|
|
76
78
|
);
|
|
77
|
-
|
|
79
|
+
let zoomOnBounding = this.getBoundsZoomLevel(boundingBox);
|
|
78
80
|
this.view.zoom = zoomOnBounding;
|
|
79
81
|
this.view.extent = newExtent;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
getBoundsZoomLevel(bounds) {
|
|
83
|
-
|
|
84
|
-
const WORLD_DIM = { height: 256, width: 256 };
|
|
85
|
-
const ZOOM_MAX = 5;
|
|
85
|
+
let mapDim = { height: this.view.height, width: this.view.width };
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
let ne = [bounds[2], bounds[3]];
|
|
88
|
+
let sw = [bounds[0], bounds[1]];
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
let latFraction = (this.latRad(ne[1]) - this.latRad(sw[1])) / Math.PI;
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
let lngDiff = ne[0] - sw[0];
|
|
93
|
+
let lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360;
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
let latZoom = this.zoom(
|
|
96
|
+
mapDim.height,
|
|
97
|
+
this.worldDimensions.height,
|
|
98
|
+
latFraction,
|
|
99
|
+
);
|
|
100
|
+
let lngZoom = this.zoom(
|
|
101
|
+
mapDim.width,
|
|
102
|
+
this.worldDimensions.width,
|
|
103
|
+
lngFraction,
|
|
104
|
+
);
|
|
97
105
|
|
|
98
|
-
return Math.min(latZoom, lngZoom,
|
|
106
|
+
return Math.min(latZoom, lngZoom, this.zoomMax);
|
|
99
107
|
//TODO calculate the corresponding level of zoom automatically
|
|
100
108
|
}
|
|
101
109
|
latRad(lat) {
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
let sin = Math.sin((lat * Math.PI) / 180);
|
|
111
|
+
let radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
|
|
104
112
|
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
|
|
105
113
|
}
|
|
106
114
|
|
|
@@ -115,11 +123,11 @@ class LayerControl {
|
|
|
115
123
|
* @returns
|
|
116
124
|
*/
|
|
117
125
|
async getPointInfo(screenPoint, options) {
|
|
118
|
-
|
|
126
|
+
let pointInformation = await this.view
|
|
119
127
|
.hitTest(screenPoint, options && options)
|
|
120
128
|
.then(function (response) {
|
|
121
129
|
if (response.results.length) {
|
|
122
|
-
|
|
130
|
+
let graphic = response.results.filter(function (result) {
|
|
123
131
|
return result.graphic;
|
|
124
132
|
});
|
|
125
133
|
return graphic[0].graphic.attributes;
|
|
@@ -129,7 +137,7 @@ class LayerControl {
|
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
getRegionInfo(region, callback) {
|
|
132
|
-
|
|
140
|
+
let xmlhttp = new XMLHttpRequest();
|
|
133
141
|
const url = `${mapViewer.spatialConfig.url}/query?where=Region+%3D+%27${region}%27&text=&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&outFields=*&returnGeometry=true&returnTrueCurves=false&maxAllowableOffset=&geometryPrecision=&outSR=&having=&returnIdsOnly=false&returnCountOnly=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&gdbVersion=&historicMoment=&returnDistinctValues=false&resultOffset=&resultRecordCount=&queryByDistance=&returnExtentOnly=false&datumTransformation=¶meterValues=&rangeValues=&quantizationParameters=&featureEncoding=esriDefault&f=pjson`;
|
|
134
142
|
xmlhttp.onreadystatechange = () => {
|
|
135
143
|
if (xmlhttp.readyState === 4 && xmlhttp.status === 200)
|
|
@@ -140,7 +148,7 @@ class LayerControl {
|
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
checkIfMorePoints(latLon, callback) {
|
|
143
|
-
|
|
151
|
+
let xmlhttp = new XMLHttpRequest();
|
|
144
152
|
const url = `${mapViewer.spatialConfig.url}/query?where=Latitude%3D+${latLon.latitude}+AND+Longitude%3D+${latLon.longitude}&text=&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&outFields=*&returnGeometry=true&returnTrueCurves=false&maxAllowableOffset=&geometryPrecision=&outSR=&having=&returnIdsOnly=false&returnCountOnly=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&gdbVersion=&historicMoment=&returnDistinctValues=false&resultOffset=&resultRecordCount=&queryByDistance=&returnExtentOnly=false&datumTransformation=¶meterValues=&rangeValues=&quantizationParameters=&featureEncoding=esriDefault&f=pjson`;
|
|
145
153
|
xmlhttp.onreadystatechange = () => {
|
|
146
154
|
if (xmlhttp.readyState === 4 && xmlhttp.status === 200)
|
|
@@ -154,6 +162,33 @@ class LayerControl {
|
|
|
154
162
|
return JSON.parse(xmlhttp.responseText);
|
|
155
163
|
}
|
|
156
164
|
|
|
165
|
+
/**
|
|
166
|
+
* It highlights the information displayed for a use case on the infoWidget.
|
|
167
|
+
* */
|
|
168
|
+
highlightInfo(response) {
|
|
169
|
+
if (response.results.length > 1) {
|
|
170
|
+
if (
|
|
171
|
+
response.results[0].graphic.geometry !== null &&
|
|
172
|
+
mapViewer.popupOnce
|
|
173
|
+
) {
|
|
174
|
+
mapViewer.popupOnce = false;
|
|
175
|
+
document.querySelector('.map').style.cursor = 'pointer';
|
|
176
|
+
document
|
|
177
|
+
.querySelector(
|
|
178
|
+
'#use_case_' + response.results[0].graphic.attributes.OBJECTID,
|
|
179
|
+
)
|
|
180
|
+
.classList.add('selected');
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
mapViewer.popupOnce = true;
|
|
184
|
+
document.querySelector('.map').style.cursor = '';
|
|
185
|
+
if (document.querySelector('.use-case-element.selected'))
|
|
186
|
+
document
|
|
187
|
+
.querySelector('.use-case-element.selected')
|
|
188
|
+
.classList.remove('selected');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
157
192
|
/**
|
|
158
193
|
* Order retreived features by Service product name
|
|
159
194
|
* @param {Object} features
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React, { createRef } from 'react';
|
|
2
|
+
//import "@arcgis/core/assets/esri/css/main.css";
|
|
3
|
+
//import "./css/ArcgisMap.css";
|
|
4
|
+
import { loadModules } from 'esri-loader';
|
|
5
|
+
var Legend;
|
|
6
|
+
|
|
7
|
+
class LegendWidget extends React.Component {
|
|
8
|
+
/**
|
|
9
|
+
* Creator of the Basemap widget class
|
|
10
|
+
* @param {*} props
|
|
11
|
+
*/
|
|
12
|
+
constructor(props) {
|
|
13
|
+
super(props);
|
|
14
|
+
this.view = props.view;
|
|
15
|
+
this.mapViewer = props.mapViewer;
|
|
16
|
+
this.container = createRef();
|
|
17
|
+
this.menuClass =
|
|
18
|
+
'esri-icon-legend esri-widget--button esri-widget esri-interactive';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
loader() {
|
|
22
|
+
return loadModules(['esri/widgets/Legend']).then(([_Legend]) => {
|
|
23
|
+
Legend = _Legend;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Method that will be invoked when the
|
|
29
|
+
* button is clicked. It controls the open
|
|
30
|
+
* and close actions of the component
|
|
31
|
+
*/
|
|
32
|
+
openMenu() {
|
|
33
|
+
if (this.mapViewer.state.showMapMenu) {
|
|
34
|
+
this.container.current.querySelector('.legend-panel').style.display =
|
|
35
|
+
'none';
|
|
36
|
+
this.container.current
|
|
37
|
+
.querySelector('.esri-widget--button')
|
|
38
|
+
.classList.replace('esri-icon-right-arrow', 'esri-icon-legend');
|
|
39
|
+
// By invoking the setState, we notify the state we want to reach
|
|
40
|
+
// and ensure that the component is rendered again
|
|
41
|
+
this.mapViewer.setState({ showMapMenu: false });
|
|
42
|
+
} else {
|
|
43
|
+
this.container.current
|
|
44
|
+
.querySelector('.esri-widget--button')
|
|
45
|
+
.classList.replace('esri-icon-legend', 'esri-icon-right-arrow');
|
|
46
|
+
this.container.current.querySelector('.legend-panel').style.display =
|
|
47
|
+
'block';
|
|
48
|
+
|
|
49
|
+
this.container.current.children[1].querySelector(
|
|
50
|
+
'.esri-legend__service-label',
|
|
51
|
+
).textContent = 'Use Cases Coverage Legend';
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
this.container.current.children[1]
|
|
55
|
+
.querySelector('.esri-legend__layer-caption')
|
|
56
|
+
.remove();
|
|
57
|
+
} catch {}
|
|
58
|
+
let legendCells = this.container.current.children[1].querySelectorAll(
|
|
59
|
+
'.esri-legend__layer-cell--info',
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < legendCells.length; i++) {
|
|
63
|
+
let currentValue = legendCells[i].textContent;
|
|
64
|
+
switch (currentValue.toLowerCase()) {
|
|
65
|
+
case 'eu':
|
|
66
|
+
legendCells[i].textContent = 'EU27+UK';
|
|
67
|
+
break;
|
|
68
|
+
case 'eea':
|
|
69
|
+
legendCells[i].textContent = 'EEA 38';
|
|
70
|
+
break;
|
|
71
|
+
case 'others':
|
|
72
|
+
legendCells[i].textContent = 'Country';
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// By invoking the setState, we notify the state we want to reach
|
|
79
|
+
// and ensure that the component is rendered again
|
|
80
|
+
this.mapViewer.setState({ showMapMenu: true });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* This method is executed after the rener method is executed
|
|
85
|
+
*/
|
|
86
|
+
async componentDidMount() {
|
|
87
|
+
await this.loader();
|
|
88
|
+
this.view.ui.add(this.container.current, 'top-right');
|
|
89
|
+
this.LegendWidget = new Legend({
|
|
90
|
+
view: this.view,
|
|
91
|
+
container: document.querySelector('.legend-panel'),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* This method renders the component
|
|
96
|
+
* @returns jsx
|
|
97
|
+
*/
|
|
98
|
+
render() {
|
|
99
|
+
return (
|
|
100
|
+
<>
|
|
101
|
+
<div
|
|
102
|
+
hidden={this.mapViewer.state.useCaseLevel === 1}
|
|
103
|
+
ref={this.container}
|
|
104
|
+
className="legend-container"
|
|
105
|
+
>
|
|
106
|
+
<div
|
|
107
|
+
className={this.menuClass}
|
|
108
|
+
id="legend_button"
|
|
109
|
+
title="Legend"
|
|
110
|
+
onClick={this.openMenu.bind(this)}
|
|
111
|
+
onKeyDown={this.openMenu.bind(this)}
|
|
112
|
+
tabIndex="0"
|
|
113
|
+
role="button"
|
|
114
|
+
></div>
|
|
115
|
+
<div className="legend-panel"></div>
|
|
116
|
+
</div>
|
|
117
|
+
</>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default LegendWidget;
|
|
@@ -36,7 +36,7 @@ class NavigationControl extends React.Component {
|
|
|
36
36
|
* @param {FeatureLayer} layer
|
|
37
37
|
*/
|
|
38
38
|
navigateToRegion(bBox, region, layer) {
|
|
39
|
-
|
|
39
|
+
let boundingBox = this.clearBBOX(bBox);
|
|
40
40
|
this.layerControl.zoomToExtent(boundingBox);
|
|
41
41
|
this.layerControl.hideLayer(layerRegion.id);
|
|
42
42
|
this.layerControl.showLayer(layerSpatial.id);
|
|
@@ -64,7 +64,7 @@ class NavigationControl extends React.Component {
|
|
|
64
64
|
* @returns Array BBox
|
|
65
65
|
*/
|
|
66
66
|
clearBBOX(stringBbox) {
|
|
67
|
-
|
|
67
|
+
let floatBbox = [];
|
|
68
68
|
// typeof stringBbox !== 'string' && (stringBbox = stringBbox.toString());
|
|
69
69
|
stringBbox = stringBbox.replace('[', '');
|
|
70
70
|
stringBbox = stringBbox.replace(']', '');
|