@eeacms/volto-arcgis-block 0.1.386 → 0.1.388
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,13 @@ 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.388](https://github.com/eea/volto-arcgis-block/compare/0.1.387...0.1.388) - 17 September 2025
|
|
8
|
+
|
|
9
|
+
#### :hammer_and_wrench: Others
|
|
10
|
+
|
|
11
|
+
- (bug): added time slider widget funciotnality for CDSE time series datasets [Unai Bolivar - [`759b719`](https://github.com/eea/volto-arcgis-block/commit/759b7193cbd046985197a6c9514d41b926f127d3)]
|
|
12
|
+
### [0.1.387](https://github.com/eea/volto-arcgis-block/compare/0.1.386...0.1.387) - 12 September 2025
|
|
13
|
+
|
|
7
14
|
### [0.1.386](https://github.com/eea/volto-arcgis-block/compare/0.1.385...0.1.386) - 12 September 2025
|
|
8
15
|
|
|
9
16
|
#### :hammer_and_wrench: Others
|
package/package.json
CHANGED
|
@@ -3924,7 +3924,6 @@ class MenuWidget extends React.Component {
|
|
|
3924
3924
|
|
|
3925
3925
|
async fullExtent(elem) {
|
|
3926
3926
|
this.url = this.layers[elem.id]?.url;
|
|
3927
|
-
// const isCDSE = !!this.url && this.url.toLowerCase().includes('/ogc/');
|
|
3928
3927
|
const isCDSE =
|
|
3929
3928
|
!!this.url &&
|
|
3930
3929
|
['/ogc/', '/cdse/'].some((s) => this.url.toLowerCase().includes(s));
|
|
@@ -4777,6 +4776,10 @@ class MenuWidget extends React.Component {
|
|
|
4777
4776
|
const isUserServiceLayer = this.state.wmsUserServiceLayers.some(
|
|
4778
4777
|
(layer) => layer.LayerId === elem.id,
|
|
4779
4778
|
);
|
|
4779
|
+
this.url = this.layers[elem.id]?.url;
|
|
4780
|
+
const isCDSE =
|
|
4781
|
+
!!this.url &&
|
|
4782
|
+
['/ogc/', '/cdse/'].some((s) => this.url.toLowerCase().includes(s));
|
|
4780
4783
|
|
|
4781
4784
|
// Only call findCheckedDataset for non-service layers (this method looks for parent datasets)
|
|
4782
4785
|
if (!isUserServiceLayer) {
|
|
@@ -4828,6 +4831,7 @@ class MenuWidget extends React.Component {
|
|
|
4828
4831
|
}
|
|
4829
4832
|
|
|
4830
4833
|
if (
|
|
4834
|
+
!isCDSE &&
|
|
4831
4835
|
!isUserServiceLayer &&
|
|
4832
4836
|
this.productId &&
|
|
4833
4837
|
this.productId.includes('333e4100b79045daa0ff16466ac83b7f')
|
|
@@ -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,48 @@ 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
|
-
|
|
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,
|
|
386
|
+
if (this.layer.type === 'wmts') {
|
|
387
|
+
this.layer.customLayerParameters = {};
|
|
388
|
+
const time = times[this.layerName].array.map(
|
|
389
|
+
(d) => new Date(d),
|
|
338
390
|
);
|
|
339
391
|
|
|
340
|
-
|
|
341
|
-
|
|
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)),
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
if (this.layer.type === 'wmts') {
|
|
370
|
-
this.layer.customLayerParameters = {};
|
|
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
|
-
}
|
|
392
|
+
for (let i in time) {
|
|
393
|
+
timeDict[time[i]] = times[this.layerName].array[i];
|
|
378
394
|
}
|
|
395
|
+
}
|
|
379
396
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
397
|
+
periodicity = Math.floor(
|
|
398
|
+
(Date.parse(times[this.layerName].array[1]) -
|
|
399
|
+
Date.parse(times[this.layerName].array[0])) /
|
|
400
|
+
86400000,
|
|
401
|
+
);
|
|
402
|
+
if (periodicity === 0) {
|
|
403
|
+
periodicity =
|
|
404
|
+
(new Date(times[this.layerName].array[1]).getHours() -
|
|
405
|
+
new Date(times[this.layerName].array[0]).getHours()) /
|
|
406
|
+
24;
|
|
391
407
|
}
|
|
392
408
|
|
|
393
409
|
this.setState({ periodicity: periodicity });
|
|
@@ -409,16 +425,6 @@ class TimesliderWidget extends React.Component {
|
|
|
409
425
|
if (!this.container.current ? true : false) {
|
|
410
426
|
this.TimesliderWidget.stop();
|
|
411
427
|
}
|
|
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
428
|
if (this.layer.type === 'wmts') {
|
|
423
429
|
this.layer.customLayerParameters = {};
|
|
424
430
|
this.layer.customLayerParameters['TIME'] =
|
|
@@ -448,7 +454,144 @@ class TimesliderWidget extends React.Component {
|
|
|
448
454
|
else {
|
|
449
455
|
this.TimesliderWidget.disabled = true;
|
|
450
456
|
}
|
|
451
|
-
}
|
|
457
|
+
} else {
|
|
458
|
+
//place getCapabilties in here
|
|
459
|
+
this.getCapabilities(this.layer.url, serviceType).then((xml) => {
|
|
460
|
+
if (this.layer.type === 'wms') {
|
|
461
|
+
times = this.parseTimeWMS(xml);
|
|
462
|
+
} else if (this.layer.type === 'wmts') {
|
|
463
|
+
times = this.parseTimeWMTS(xml);
|
|
464
|
+
}
|
|
465
|
+
// Capabilities have time enabled
|
|
466
|
+
if (
|
|
467
|
+
times[this.layerName].hasOwnProperty('dimension') === false
|
|
468
|
+
) {
|
|
469
|
+
// Start-End-Period
|
|
470
|
+
if (times[this.layerName].hasOwnProperty('period')) {
|
|
471
|
+
this.TimesliderWidget.fullTimeExtent = new TimeExtent({
|
|
472
|
+
start: new Date(times[this.layerName].start),
|
|
473
|
+
end: new Date(times[this.layerName].end),
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
const period = this.parserPeriod(
|
|
477
|
+
times[this.layerName].period,
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
this.TimesliderWidget.stops = {
|
|
481
|
+
interval: {
|
|
482
|
+
value:
|
|
483
|
+
period.years * 365 * 24 * 60 +
|
|
484
|
+
period.months * 31 * 24 * 60 +
|
|
485
|
+
period.weeks * 7 * 24 * 60 +
|
|
486
|
+
period.days * 24 * 60 +
|
|
487
|
+
period.hours * 60 +
|
|
488
|
+
period.minutes +
|
|
489
|
+
period.seconds / 60,
|
|
490
|
+
unit: 'minutes',
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
periodicity = times[this.layerName].period;
|
|
495
|
+
} else if (times[this.layerName].hasOwnProperty('array')) {
|
|
496
|
+
// Dates array
|
|
497
|
+
this.TimesliderWidget.fullTimeExtent = new TimeExtent({
|
|
498
|
+
start: new Date(times[this.layerName].array[0]),
|
|
499
|
+
end: new Date(
|
|
500
|
+
times[this.layerName].array[
|
|
501
|
+
times[this.layerName].array.length - 1
|
|
502
|
+
],
|
|
503
|
+
),
|
|
504
|
+
});
|
|
505
|
+
this.TimesliderWidget.stops = {
|
|
506
|
+
dates: times[this.layerName].array.map(
|
|
507
|
+
(e) => new Date(e),
|
|
508
|
+
),
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
if (this.layer.type === 'wmts') {
|
|
512
|
+
this.layer.customLayerParameters = {};
|
|
513
|
+
const time = times[this.layerName].array.map(
|
|
514
|
+
(d) => new Date(d),
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
for (let i in time) {
|
|
518
|
+
timeDict[time[i]] = times[this.layerName].array[i];
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
periodicity = Math.floor(
|
|
523
|
+
(Date.parse(times[this.layerName].array[1]) -
|
|
524
|
+
Date.parse(times[this.layerName].array[0])) /
|
|
525
|
+
86400000,
|
|
526
|
+
);
|
|
527
|
+
if (periodicity === 0) {
|
|
528
|
+
periodicity =
|
|
529
|
+
(new Date(times[this.layerName].array[1]).getHours() -
|
|
530
|
+
new Date(times[this.layerName].array[0]).getHours()) /
|
|
531
|
+
24;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
this.setState({ periodicity: periodicity });
|
|
536
|
+
if (this.TimesliderWidget.effectiveStops.length === 11) {
|
|
537
|
+
let period =
|
|
538
|
+
(this.TimesliderWidget.fullTimeExtent.end -
|
|
539
|
+
this.TimesliderWidget.fullTimeExtent.start) /
|
|
540
|
+
590000000;
|
|
541
|
+
if (period > this.TimesliderWidget.stops.interval.value) {
|
|
542
|
+
this.TimesliderWidget.stops = {
|
|
543
|
+
interval: {
|
|
544
|
+
value: period,
|
|
545
|
+
unit: 'minutes',
|
|
546
|
+
},
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
this.TimesliderWidget.watch('timeExtent', (timeExtent) => {
|
|
551
|
+
if (!this.container.current ? true : false) {
|
|
552
|
+
this.TimesliderWidget.stop();
|
|
553
|
+
}
|
|
554
|
+
// let start = new Date(timeExtent.start).getTime();
|
|
555
|
+
// let end = new Date(timeExtent.end).getTime();
|
|
556
|
+
// this.props.time.elem.setAttribute('time-start', start);
|
|
557
|
+
// this.props.time.elem.setAttribute('time-end', end);
|
|
558
|
+
// if (this.props.download) {
|
|
559
|
+
// this.props.time.dataset.setAttribute('time-start', start);
|
|
560
|
+
// this.props.time.dataset.setAttribute('time-end', end);
|
|
561
|
+
// }
|
|
562
|
+
// this.props.time.dataset.setAttribute('time-start', start);
|
|
563
|
+
// this.props.time.dataset.setAttribute('time-end', end);
|
|
564
|
+
if (this.layer.type === 'wmts') {
|
|
565
|
+
this.layer.customLayerParameters = {};
|
|
566
|
+
this.layer.customLayerParameters['TIME'] =
|
|
567
|
+
timeDict[this.TimesliderWidget.timeExtent.end];
|
|
568
|
+
} else {
|
|
569
|
+
this.layer.customLayerParameters = {};
|
|
570
|
+
if (times[this.layerName].hasOwnProperty('array')) {
|
|
571
|
+
this.layer.customLayerParameters['TIME'] =
|
|
572
|
+
timeDict[this.TimesliderWidget.timeExtent.end];
|
|
573
|
+
} else {
|
|
574
|
+
const newDateTimeObject = new Date(
|
|
575
|
+
this.TimesliderWidget.timeExtent.start.toISOString(),
|
|
576
|
+
);
|
|
577
|
+
newDateTimeObject.setMinutes(
|
|
578
|
+
this.TimesliderWidget.timeExtent.start.getMinutes() +
|
|
579
|
+
this.TimesliderWidget.stops['interval'].value,
|
|
580
|
+
);
|
|
581
|
+
this.layer.customLayerParameters['TIME'] =
|
|
582
|
+
this.TimesliderWidget.timeExtent.start.toISOString() +
|
|
583
|
+
'/' +
|
|
584
|
+
newDateTimeObject.toISOString(); //OK
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
this.layer.refresh();
|
|
588
|
+
});
|
|
589
|
+
} // if there is dimension time
|
|
590
|
+
else {
|
|
591
|
+
this.TimesliderWidget.disabled = true;
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
}
|
|
452
595
|
} // is feature or WMS/WMTS
|
|
453
596
|
});
|
|
454
597
|
});
|