@eeacms/volto-arcgis-block 0.1.387 → 0.1.389
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,17 @@ 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.389](https://github.com/eea/volto-arcgis-block/compare/0.1.388...0.1.389) - 18 September 2025
|
|
8
|
+
|
|
9
|
+
#### :hammer_and_wrench: Others
|
|
10
|
+
|
|
11
|
+
- Merge pull request #1018 from eea/CLMS-291307-ADAPT-DATA-VIEWER-TIME-SLIDER-FOR-CDSE-TIME-SERIES-DATASETS [Unai Bolivar - [`da9c70f`](https://github.com/eea/volto-arcgis-block/commit/da9c70f56b030432f95b07487775be947d6c668c)]
|
|
12
|
+
- (bug): time slider widget turns off logo for cdse tiles [Unai Bolivar - [`555b466`](https://github.com/eea/volto-arcgis-block/commit/555b466b3fe54ca44a20c97102846651d825f7ef)]
|
|
13
|
+
### [0.1.388](https://github.com/eea/volto-arcgis-block/compare/0.1.387...0.1.388) - 17 September 2025
|
|
14
|
+
|
|
15
|
+
#### :hammer_and_wrench: Others
|
|
16
|
+
|
|
17
|
+
- (bug): added time slider widget funciotnality for CDSE time series datasets [Unai Bolivar - [`759b719`](https://github.com/eea/volto-arcgis-block/commit/759b7193cbd046985197a6c9514d41b926f127d3)]
|
|
7
18
|
### [0.1.387](https://github.com/eea/volto-arcgis-block/compare/0.1.386...0.1.387) - 12 September 2025
|
|
8
19
|
|
|
9
20
|
### [0.1.386](https://github.com/eea/volto-arcgis-block/compare/0.1.385...0.1.386) - 12 September 2025
|
package/package.json
CHANGED
|
@@ -3850,7 +3850,6 @@ class MenuWidget extends React.Component {
|
|
|
3850
3850
|
} else {
|
|
3851
3851
|
this.url = serviceLayer.ViewService;
|
|
3852
3852
|
}
|
|
3853
|
-
// const isCDSE = !!this.url && this.url.toLowerCase().includes('/ogc/');
|
|
3854
3853
|
const isCDSE =
|
|
3855
3854
|
!!this.url &&
|
|
3856
3855
|
['/ogc/', '/cdse/'].some((s) => this.url.toLowerCase().includes(s));
|
|
@@ -84,6 +84,46 @@ class TimesliderWidget extends React.Component {
|
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
async getCDSEWFSTemporalData(url, layer) {
|
|
88
|
+
if (!url) return {};
|
|
89
|
+
const match = /\/ogc\/(?:wmts|wms)\/([^/?]+)/i.exec(url);
|
|
90
|
+
const datasetDownloadInformation =
|
|
91
|
+
layer?.DatasetDownloadInformation ||
|
|
92
|
+
layer?.DatasetDownloadInformation ||
|
|
93
|
+
{};
|
|
94
|
+
if (!datasetDownloadInformation) return {};
|
|
95
|
+
const byocCollectionId =
|
|
96
|
+
datasetDownloadInformation?.items[0].byoc_collection || null;
|
|
97
|
+
if (!byocCollectionId) return {};
|
|
98
|
+
if (!match) return {};
|
|
99
|
+
const fetchUrl = `https://sh.dataspace.copernicus.eu/ogc/wfs/${match[1]}?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=byoc-${byocCollectionId}&COUNT=100&BBOX=-21039383,-22375217,21039383,22375217&OUTPUTFORMAT=application/json`;
|
|
100
|
+
try {
|
|
101
|
+
const res = await fetch(fetchUrl);
|
|
102
|
+
const data = await res.json();
|
|
103
|
+
let times = {};
|
|
104
|
+
let layerName = '';
|
|
105
|
+
if (layer?.type === 'feature') {
|
|
106
|
+
layerName = layer?.id;
|
|
107
|
+
} else if (layer?.type === 'wms') {
|
|
108
|
+
layerName = layer?.sublayers?.items?.[0]?.name;
|
|
109
|
+
} else if (layer?.type === 'wmts') {
|
|
110
|
+
layerName = layer?.activeLayer?.id;
|
|
111
|
+
} else {
|
|
112
|
+
layerName = layer?.name || layer?.title || layer?.id || 'layer';
|
|
113
|
+
}
|
|
114
|
+
const features = Array.isArray(data?.features) ? data.features : [];
|
|
115
|
+
const dates = features
|
|
116
|
+
.map((f) => f?.properties?.date || null)
|
|
117
|
+
.filter((v) => v);
|
|
118
|
+
if (dates.length > 0) {
|
|
119
|
+
times[layerName] = {
|
|
120
|
+
array: dates,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return times;
|
|
124
|
+
} catch (e) {}
|
|
125
|
+
}
|
|
126
|
+
|
|
87
127
|
parseTimeWMS(xml) {
|
|
88
128
|
let layers = Array.from(xml.querySelectorAll('Layer')).filter(
|
|
89
129
|
(v) => v.querySelectorAll('Layer').length === 0,
|
|
@@ -287,7 +327,14 @@ class TimesliderWidget extends React.Component {
|
|
|
287
327
|
|
|
288
328
|
this.props.view
|
|
289
329
|
.whenLayerView(this.layer, this.TimesliderWidget)
|
|
290
|
-
.then((lv) => {
|
|
330
|
+
.then(async (lv) => {
|
|
331
|
+
this.url = lv?.layer?.viewService ?? this.layer?.url ?? null;
|
|
332
|
+
const urlNorm =
|
|
333
|
+
typeof this.url === 'string'
|
|
334
|
+
? this.url.replace(/%2F/gi, '/').toLowerCase()
|
|
335
|
+
: '';
|
|
336
|
+
const isCDSE =
|
|
337
|
+
urlNorm.includes('/ogc/') || urlNorm.includes('/cdse/');
|
|
291
338
|
if (this.layer.type === 'feature') {
|
|
292
339
|
this.TimesliderWidget.fullTimeExtent = this.layer.timeInfo.fullTimeExtent;
|
|
293
340
|
this.TimesliderWidget.stops = {
|
|
@@ -315,79 +362,50 @@ class TimesliderWidget extends React.Component {
|
|
|
315
362
|
} else if (this.layer.type === 'wmts') {
|
|
316
363
|
serviceType = 'wmts';
|
|
317
364
|
}
|
|
365
|
+
let times = {};
|
|
366
|
+
let periodicity;
|
|
367
|
+
if (isCDSE) {
|
|
368
|
+
times = await this.getCDSEWFSTemporalData(
|
|
369
|
+
this.layer.url,
|
|
370
|
+
this.layer,
|
|
371
|
+
);
|
|
372
|
+
if (times) {
|
|
373
|
+
// Dates array
|
|
374
|
+
this.TimesliderWidget.fullTimeExtent = new TimeExtent({
|
|
375
|
+
start: new Date(
|
|
376
|
+
times[this.layerName].array[
|
|
377
|
+
times[this.layerName].array.length - 1
|
|
378
|
+
],
|
|
379
|
+
),
|
|
380
|
+
end: new Date(times[this.layerName].array[0]),
|
|
381
|
+
});
|
|
382
|
+
this.TimesliderWidget.stops = {
|
|
383
|
+
dates: times[this.layerName].array.map((e) => new Date(e)),
|
|
384
|
+
};
|
|
318
385
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (this.layer.type === 'wms') {
|
|
323
|
-
times = this.parseTimeWMS(xml);
|
|
324
|
-
} else if (this.layer.type === 'wmts') {
|
|
325
|
-
times = this.parseTimeWMTS(xml);
|
|
326
|
-
}
|
|
327
|
-
// Capabilities have time enabled
|
|
328
|
-
if (times[this.layerName].hasOwnProperty('dimension') === false) {
|
|
329
|
-
// Start-End-Period
|
|
330
|
-
if (times[this.layerName].hasOwnProperty('period')) {
|
|
331
|
-
this.TimesliderWidget.fullTimeExtent = new TimeExtent({
|
|
332
|
-
start: new Date(times[this.layerName].start),
|
|
333
|
-
end: new Date(times[this.layerName].end),
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
const period = this.parserPeriod(
|
|
337
|
-
times[this.layerName].period,
|
|
338
|
-
);
|
|
339
|
-
|
|
340
|
-
this.TimesliderWidget.stops = {
|
|
341
|
-
interval: {
|
|
342
|
-
value:
|
|
343
|
-
period.years * 365 * 24 * 60 +
|
|
344
|
-
period.months * 31 * 24 * 60 +
|
|
345
|
-
period.weeks * 7 * 24 * 60 +
|
|
346
|
-
period.days * 24 * 60 +
|
|
347
|
-
period.hours * 60 +
|
|
348
|
-
period.minutes +
|
|
349
|
-
period.seconds / 60,
|
|
350
|
-
unit: 'minutes',
|
|
351
|
-
},
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
periodicity = times[this.layerName].period;
|
|
355
|
-
} else if (times[this.layerName].hasOwnProperty('array')) {
|
|
356
|
-
// Dates array
|
|
357
|
-
this.TimesliderWidget.fullTimeExtent = new TimeExtent({
|
|
358
|
-
start: new Date(times[this.layerName].array[0]),
|
|
359
|
-
end: new Date(
|
|
360
|
-
times[this.layerName].array[
|
|
361
|
-
times[this.layerName].array.length - 1
|
|
362
|
-
],
|
|
363
|
-
),
|
|
364
|
-
});
|
|
365
|
-
this.TimesliderWidget.stops = {
|
|
366
|
-
dates: times[this.layerName].array.map((e) => new Date(e)),
|
|
386
|
+
if (this.layer.type === 'wmts') {
|
|
387
|
+
this.layer.customLayerParameters = {
|
|
388
|
+
SHOWLOGO: false,
|
|
367
389
|
};
|
|
390
|
+
const time = times[this.layerName].array.map(
|
|
391
|
+
(d) => new Date(d),
|
|
392
|
+
);
|
|
368
393
|
|
|
369
|
-
|
|
370
|
-
this.
|
|
371
|
-
const time = times[this.layerName].array.map(
|
|
372
|
-
(d) => new Date(d),
|
|
373
|
-
);
|
|
374
|
-
|
|
375
|
-
for (let i in time) {
|
|
376
|
-
timeDict[time[i]] = times[this.layerName].array[i];
|
|
377
|
-
}
|
|
394
|
+
for (let i in time) {
|
|
395
|
+
timeDict[time[i]] = times[this.layerName].array[i];
|
|
378
396
|
}
|
|
397
|
+
}
|
|
379
398
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
399
|
+
periodicity = Math.floor(
|
|
400
|
+
(Date.parse(times[this.layerName].array[1]) -
|
|
401
|
+
Date.parse(times[this.layerName].array[0])) /
|
|
402
|
+
86400000,
|
|
403
|
+
);
|
|
404
|
+
if (periodicity === 0) {
|
|
405
|
+
periodicity =
|
|
406
|
+
(new Date(times[this.layerName].array[1]).getHours() -
|
|
407
|
+
new Date(times[this.layerName].array[0]).getHours()) /
|
|
408
|
+
24;
|
|
391
409
|
}
|
|
392
410
|
|
|
393
411
|
this.setState({ periodicity: periodicity });
|
|
@@ -409,18 +427,10 @@ class TimesliderWidget extends React.Component {
|
|
|
409
427
|
if (!this.container.current ? true : false) {
|
|
410
428
|
this.TimesliderWidget.stop();
|
|
411
429
|
}
|
|
412
|
-
/*let start = new Date(timeExtent.start).getTime();
|
|
413
|
-
let end = new Date(timeExtent.end).getTime();
|
|
414
|
-
this.props.time.elem.setAttribute('time-start', start);
|
|
415
|
-
this.props.time.elem.setAttribute('time-end', end);
|
|
416
|
-
if (this.props.download) {
|
|
417
|
-
this.props.time.dataset.setAttribute('time-start', start);
|
|
418
|
-
this.props.time.dataset.setAttribute('time-end', end);
|
|
419
|
-
}
|
|
420
|
-
this.props.time.dataset.setAttribute('time-start', start);
|
|
421
|
-
this.props.time.dataset.setAttribute('time-end', end);*/
|
|
422
430
|
if (this.layer.type === 'wmts') {
|
|
423
|
-
this.layer.customLayerParameters = {
|
|
431
|
+
this.layer.customLayerParameters = {
|
|
432
|
+
SHOWLOGO: false,
|
|
433
|
+
};
|
|
424
434
|
this.layer.customLayerParameters['TIME'] =
|
|
425
435
|
timeDict[this.TimesliderWidget.timeExtent.end];
|
|
426
436
|
} else {
|
|
@@ -448,7 +458,144 @@ class TimesliderWidget extends React.Component {
|
|
|
448
458
|
else {
|
|
449
459
|
this.TimesliderWidget.disabled = true;
|
|
450
460
|
}
|
|
451
|
-
}
|
|
461
|
+
} else {
|
|
462
|
+
//place getCapabilties in here
|
|
463
|
+
this.getCapabilities(this.layer.url, serviceType).then((xml) => {
|
|
464
|
+
if (this.layer.type === 'wms') {
|
|
465
|
+
times = this.parseTimeWMS(xml);
|
|
466
|
+
} else if (this.layer.type === 'wmts') {
|
|
467
|
+
times = this.parseTimeWMTS(xml);
|
|
468
|
+
}
|
|
469
|
+
// Capabilities have time enabled
|
|
470
|
+
if (
|
|
471
|
+
times[this.layerName].hasOwnProperty('dimension') === false
|
|
472
|
+
) {
|
|
473
|
+
// Start-End-Period
|
|
474
|
+
if (times[this.layerName].hasOwnProperty('period')) {
|
|
475
|
+
this.TimesliderWidget.fullTimeExtent = new TimeExtent({
|
|
476
|
+
start: new Date(times[this.layerName].start),
|
|
477
|
+
end: new Date(times[this.layerName].end),
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
const period = this.parserPeriod(
|
|
481
|
+
times[this.layerName].period,
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
this.TimesliderWidget.stops = {
|
|
485
|
+
interval: {
|
|
486
|
+
value:
|
|
487
|
+
period.years * 365 * 24 * 60 +
|
|
488
|
+
period.months * 31 * 24 * 60 +
|
|
489
|
+
period.weeks * 7 * 24 * 60 +
|
|
490
|
+
period.days * 24 * 60 +
|
|
491
|
+
period.hours * 60 +
|
|
492
|
+
period.minutes +
|
|
493
|
+
period.seconds / 60,
|
|
494
|
+
unit: 'minutes',
|
|
495
|
+
},
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
periodicity = times[this.layerName].period;
|
|
499
|
+
} else if (times[this.layerName].hasOwnProperty('array')) {
|
|
500
|
+
// Dates array
|
|
501
|
+
this.TimesliderWidget.fullTimeExtent = new TimeExtent({
|
|
502
|
+
start: new Date(times[this.layerName].array[0]),
|
|
503
|
+
end: new Date(
|
|
504
|
+
times[this.layerName].array[
|
|
505
|
+
times[this.layerName].array.length - 1
|
|
506
|
+
],
|
|
507
|
+
),
|
|
508
|
+
});
|
|
509
|
+
this.TimesliderWidget.stops = {
|
|
510
|
+
dates: times[this.layerName].array.map(
|
|
511
|
+
(e) => new Date(e),
|
|
512
|
+
),
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
if (this.layer.type === 'wmts') {
|
|
516
|
+
this.layer.customLayerParameters = {};
|
|
517
|
+
const time = times[this.layerName].array.map(
|
|
518
|
+
(d) => new Date(d),
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
for (let i in time) {
|
|
522
|
+
timeDict[time[i]] = times[this.layerName].array[i];
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
periodicity = Math.floor(
|
|
527
|
+
(Date.parse(times[this.layerName].array[1]) -
|
|
528
|
+
Date.parse(times[this.layerName].array[0])) /
|
|
529
|
+
86400000,
|
|
530
|
+
);
|
|
531
|
+
if (periodicity === 0) {
|
|
532
|
+
periodicity =
|
|
533
|
+
(new Date(times[this.layerName].array[1]).getHours() -
|
|
534
|
+
new Date(times[this.layerName].array[0]).getHours()) /
|
|
535
|
+
24;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
this.setState({ periodicity: periodicity });
|
|
540
|
+
if (this.TimesliderWidget.effectiveStops.length === 11) {
|
|
541
|
+
let period =
|
|
542
|
+
(this.TimesliderWidget.fullTimeExtent.end -
|
|
543
|
+
this.TimesliderWidget.fullTimeExtent.start) /
|
|
544
|
+
590000000;
|
|
545
|
+
if (period > this.TimesliderWidget.stops.interval.value) {
|
|
546
|
+
this.TimesliderWidget.stops = {
|
|
547
|
+
interval: {
|
|
548
|
+
value: period,
|
|
549
|
+
unit: 'minutes',
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
this.TimesliderWidget.watch('timeExtent', (timeExtent) => {
|
|
555
|
+
if (!this.container.current ? true : false) {
|
|
556
|
+
this.TimesliderWidget.stop();
|
|
557
|
+
}
|
|
558
|
+
// let start = new Date(timeExtent.start).getTime();
|
|
559
|
+
// let end = new Date(timeExtent.end).getTime();
|
|
560
|
+
// this.props.time.elem.setAttribute('time-start', start);
|
|
561
|
+
// this.props.time.elem.setAttribute('time-end', end);
|
|
562
|
+
// if (this.props.download) {
|
|
563
|
+
// this.props.time.dataset.setAttribute('time-start', start);
|
|
564
|
+
// this.props.time.dataset.setAttribute('time-end', end);
|
|
565
|
+
// }
|
|
566
|
+
// this.props.time.dataset.setAttribute('time-start', start);
|
|
567
|
+
// this.props.time.dataset.setAttribute('time-end', end);
|
|
568
|
+
if (this.layer.type === 'wmts') {
|
|
569
|
+
this.layer.customLayerParameters = {};
|
|
570
|
+
this.layer.customLayerParameters['TIME'] =
|
|
571
|
+
timeDict[this.TimesliderWidget.timeExtent.end];
|
|
572
|
+
} else {
|
|
573
|
+
this.layer.customLayerParameters = {};
|
|
574
|
+
if (times[this.layerName].hasOwnProperty('array')) {
|
|
575
|
+
this.layer.customLayerParameters['TIME'] =
|
|
576
|
+
timeDict[this.TimesliderWidget.timeExtent.end];
|
|
577
|
+
} else {
|
|
578
|
+
const newDateTimeObject = new Date(
|
|
579
|
+
this.TimesliderWidget.timeExtent.start.toISOString(),
|
|
580
|
+
);
|
|
581
|
+
newDateTimeObject.setMinutes(
|
|
582
|
+
this.TimesliderWidget.timeExtent.start.getMinutes() +
|
|
583
|
+
this.TimesliderWidget.stops['interval'].value,
|
|
584
|
+
);
|
|
585
|
+
this.layer.customLayerParameters['TIME'] =
|
|
586
|
+
this.TimesliderWidget.timeExtent.start.toISOString() +
|
|
587
|
+
'/' +
|
|
588
|
+
newDateTimeObject.toISOString(); //OK
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
this.layer.refresh();
|
|
592
|
+
});
|
|
593
|
+
} // if there is dimension time
|
|
594
|
+
else {
|
|
595
|
+
this.TimesliderWidget.disabled = true;
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
}
|
|
452
599
|
} // is feature or WMS/WMTS
|
|
453
600
|
});
|
|
454
601
|
});
|