@eeacms/volto-arcgis-block 0.1.387 → 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,11 @@ 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)]
7
12
  ### [0.1.387](https://github.com/eea/volto-arcgis-block/compare/0.1.386...0.1.387) - 12 September 2025
8
13
 
9
14
  ### [0.1.386](https://github.com/eea/volto-arcgis-block/compare/0.1.385...0.1.386) - 12 September 2025
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-arcgis-block",
3
- "version": "0.1.387",
3
+ "version": "0.1.388",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -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
- this.getCapabilities(this.layer.url, serviceType).then((xml) => {
320
- let times = {};
321
- let periodicity;
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,
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
- 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)),
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
- periodicity = Math.floor(
381
- (Date.parse(times[this.layerName].array[1]) -
382
- Date.parse(times[this.layerName].array[0])) /
383
- 86400000,
384
- );
385
- if (periodicity === 0) {
386
- periodicity =
387
- (new Date(times[this.layerName].array[1]).getHours() -
388
- new Date(times[this.layerName].array[0]).getHours()) /
389
- 24;
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
  });