@opengeoweb/webmap 2.1.4 → 2.2.0

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/index.esm.js CHANGED
@@ -492,6 +492,14 @@ var addStylesForLayer = function addStylesForLayer(layerObjectFromWMS) {
492
492
  });
493
493
  };
494
494
 
495
+ /**
496
+ * Returns the current time in ms
497
+ * @returns the current time in ms
498
+ */
499
+
500
+ var getCurrentImageTime = function getCurrentImageTime() {
501
+ return new Date().getTime();
502
+ };
495
503
  /**
496
504
  * WMImage provides an API to the HTML image element. It is used for caching and easier access to images.
497
505
  */
@@ -513,6 +521,8 @@ var WMImage = /*#__PURE__*/function () {
513
521
  this._isLoaded = undefined;
514
522
  this._isLoading = undefined;
515
523
  this._hasError = undefined;
524
+ this._imageTimeStampAtError = getCurrentImageTime();
525
+ this._numFailedAttempts = 0;
516
526
  this.srcToLoad = src;
517
527
  this.loadEventCallback = callback;
518
528
  this.el = new Image();
@@ -531,6 +541,9 @@ var WMImage = /*#__PURE__*/function () {
531
541
  this.hasError = this.hasError.bind(this);
532
542
  this._load = this._load.bind(this);
533
543
  this.load = this.load.bind(this);
544
+ this.forceReload = this.forceReload.bind(this);
545
+ this.getLastErrorMSecondsAgo = this.getLastErrorMSecondsAgo.bind(this);
546
+ this.getNumFailedAttempts = this.getNumFailedAttempts.bind(this);
534
547
  this._loadEvent = this._loadEvent.bind(this);
535
548
  this.getWidth = this.getWidth.bind(this);
536
549
  this.getHeight = this.getHeight.bind(this);
@@ -541,6 +554,9 @@ var WMImage = /*#__PURE__*/function () {
541
554
  _this._loadEvent(false);
542
555
  });
543
556
  this.el.addEventListener('error', function () {
557
+ _this._imageTimeStampAtError = getCurrentImageTime();
558
+ _this._numFailedAttempts += 1;
559
+
544
560
  _this._loadEvent(true);
545
561
  });
546
562
 
@@ -560,6 +576,8 @@ var WMImage = /*#__PURE__*/function () {
560
576
  this._isLoaded = false;
561
577
  this._isLoading = false;
562
578
  this._hasError = false;
579
+ this._numFailedAttempts = 0;
580
+ this._imageTimeStampAtError = getCurrentImageTime();
563
581
  }
564
582
  /**
565
583
  * Returns true if the image has been loaded
@@ -580,6 +598,25 @@ var WMImage = /*#__PURE__*/function () {
580
598
  value: function isLoading() {
581
599
  return this._isLoading;
582
600
  }
601
+ /**
602
+ * Get the amount of milliseconds since the image experienced an image load.
603
+ * @returns milliseconds since the image had an error
604
+ */
605
+
606
+ }, {
607
+ key: "getLastErrorMSecondsAgo",
608
+ value: function getLastErrorMSecondsAgo() {
609
+ return getCurrentImageTime() - this._imageTimeStampAtError;
610
+ }
611
+ /**
612
+ * @returns The number of failed attempts for this image
613
+ */
614
+
615
+ }, {
616
+ key: "getNumFailedAttempts",
617
+ value: function getNumFailedAttempts() {
618
+ return this._numFailedAttempts;
619
+ }
583
620
  /**
584
621
  * Set source of image, but it will not load the image yet.
585
622
  * @param src URL of the image to load
@@ -605,6 +642,8 @@ var WMImage = /*#__PURE__*/function () {
605
642
  return;
606
643
  }
607
644
 
645
+ this._numFailedAttempts = 0;
646
+ this._imageTimeStampAtError = getCurrentImageTime();
608
647
  this._isLoaded = false;
609
648
  }
610
649
  /**
@@ -644,6 +683,14 @@ var WMImage = /*#__PURE__*/function () {
644
683
  this._load();
645
684
  }
646
685
  }, {
686
+ key: "forceReload",
687
+ value: function forceReload() {
688
+ this._isLoaded = false;
689
+ this._srcLoaded = undefined;
690
+
691
+ this._load();
692
+ }
693
+ }, {
647
694
  key: "_getImageWithHeaders",
648
695
  value: function _getImageWithHeaders(url, headers) {
649
696
  var _this2 = this;
@@ -714,8 +761,12 @@ var WMImage = /*#__PURE__*/function () {
714
761
  var hostName = "".concat(splittedHREF[0], "//").concat(splittedHREF[1], "/");
715
762
  this.srcToLoad = hostName + this.srcToLoad;
716
763
  }
764
+ /*
765
+ * If the image has already loaded this source succesfully (without error), simply trigger the loadevent.
766
+ */
717
767
 
718
- if (this.srcToLoad === this._srcLoaded) {
768
+
769
+ if (this.srcToLoad === this._srcLoaded && !this._hasError) {
719
770
  this._loadEvent(false);
720
771
 
721
772
  return;
@@ -1337,13 +1388,14 @@ var addAlternativeImage = function addAlternativeImage(newLayer) {
1337
1388
  /* It is not in the list, so add it */
1338
1389
 
1339
1390
  if (imageIsAlreadyIndex === -1) {
1340
- sharedImagesList[sigImageUrl].push(newLayer);
1341
- }
1342
- /* Ensure that the oldest images are removed, keep a maximum of 10 images per signature url */
1391
+ /* Ensure that the oldest images are removed, keep a maximum of 10 images per signature url */
1392
+ while (sharedImagesList[sigImageUrl].length >= 10) {
1393
+ sharedImagesList[sigImageUrl].pop();
1394
+ }
1395
+ /* Add it to the beginning of the array for efficieny in searching at a later stage */
1343
1396
 
1344
1397
 
1345
- while (sharedImagesList[sigImageUrl].length > 10) {
1346
- sharedImagesList[sigImageUrl].splice(0, 1);
1398
+ sharedImagesList[sigImageUrl].unshift(newLayer);
1347
1399
  }
1348
1400
  };
1349
1401
  /**
@@ -1368,38 +1420,17 @@ var removeAlternativeImage = function removeAlternativeImage(imageUrl) {
1368
1420
  }
1369
1421
  };
1370
1422
  /**
1371
- * Algorithm two determine how much two bboxes are similar
1372
- * @param rect1
1373
- * @param rect2
1374
- * @returns
1375
- */
1376
-
1377
- var geClosestBBox = function geClosestBBox(rect1, rect2) {
1378
- var diffTLX = rect1.left - rect2.left;
1379
- var diffTLY = rect1.top - rect2.top;
1380
- var diffBRX = rect1.right - rect2.right;
1381
- var diffBRY = rect1.bottom - rect2.bottom;
1382
- return Math.sqrt(diffTLX * diffTLX + diffTLY * diffTLY) + Math.sqrt(diffBRX * diffBRX + diffBRY * diffBRY);
1383
- };
1384
- /**
1385
- * Sort the imageslist by overlapping area, highest area first
1423
+ * Sort the imageslist by imagedate, newewst image first.
1386
1424
  * @param imagesList
1387
- * @param bbox
1388
1425
  * @returns
1389
1426
  */
1390
1427
 
1391
- var sortByOverlappingArea = function sortByOverlappingArea(imagesList, bbox) {
1392
- var toSort = imagesList.map(function (im) {
1393
- return {
1394
- dist: geClosestBBox(im.bbox, bbox),
1395
- image: im
1396
- };
1397
- });
1398
- var sorted = toSort.sort(function (a, b) {
1399
- return a.dist > b.dist ? 1 : -1;
1428
+ var sortByImageDate = function sortByImageDate(imagesList) {
1429
+ var sorted = imagesList.sort(function (a, b) {
1430
+ return a.imageAge < b.imageAge ? 1 : -1;
1400
1431
  });
1401
1432
  return sorted.map(function (i) {
1402
- return i.image;
1433
+ return i;
1403
1434
  });
1404
1435
  };
1405
1436
  /**
@@ -1410,17 +1441,18 @@ var sortByOverlappingArea = function sortByOverlappingArea(imagesList, bbox) {
1410
1441
  * @returns A canvasLayer, containing the new image source with its geo properties
1411
1442
  */
1412
1443
 
1413
- var getAlternativeImage = function getAlternativeImage(imageUrl, imageStore, bbox) {
1444
+ var getAlternativeImage = function getAlternativeImage(imageUrl, imageStore, // eslint-disable-next-line no-unused-vars
1445
+ _bbox) {
1414
1446
  var sigImageUrl = makeQueryStringWithoutGeoInfo(imageUrl);
1415
1447
  var imagesForUrl = sharedImagesList[sigImageUrl];
1416
1448
 
1417
1449
  if (imagesForUrl && imagesForUrl.length > 0) {
1418
- var sortedImagesForUrl = sortByOverlappingArea(imagesForUrl, bbox);
1419
- /* Find the first image in this list which is also loaded */
1450
+ var sortedImagesForUrl = sortByImageDate(imagesForUrl);
1451
+ /* Find the first image in this list which is also loaded and has no error */
1420
1452
 
1421
1453
  var index = sortedImagesForUrl.findIndex(function (altImage) {
1422
1454
  var cachedImage = imageStore.getImageForSrc(altImage.imageSource);
1423
- return cachedImage && cachedImage.isLoaded();
1455
+ return cachedImage && cachedImage.isLoaded() && !cachedImage.isLoading() && !cachedImage.hasError();
1424
1456
  });
1425
1457
  if (index !== -1) return sortedImagesForUrl[index];
1426
1458
  }
@@ -1588,16 +1620,29 @@ var WMCanvasBuffer = /*#__PURE__*/function () {
1588
1620
  for (var j = 0; j < this.layers.length; j += 1) {
1589
1621
  var imageToDisplay = this._imageStore.getImageForSrc(this.layers[j].imageSource);
1590
1622
 
1591
- if (!imageToDisplay || imageToDisplay.isLoaded() === false) {
1592
- /* Find closest image */
1623
+ if (imageToDisplay && imageToDisplay.isLoaded() && !imageToDisplay.isLoading() && !imageToDisplay.hasError()) {
1624
+ // Draw this image, it is loaded and OK
1625
+ this._drawImage(this.layers[j]);
1626
+ } else {
1627
+ /**
1628
+ * Check if this image has an error.
1629
+ * If the error has occured some time ago, and the amount of retries is low, just retry to load the image.
1630
+ */
1631
+ if (imageToDisplay.hasError()) {
1632
+ if (imageToDisplay.isLoading() === false && imageToDisplay.getLastErrorMSecondsAgo() > 5000) {
1633
+ if (imageToDisplay.getNumFailedAttempts() < 10) {
1634
+ imageToDisplay.forceReload();
1635
+ }
1636
+ }
1637
+ }
1638
+ /* Find closest alternative and display instead image */
1639
+
1640
+
1593
1641
  var im = getAlternativeImage(this.layers[j].imageSource, this._imageStore, this._currentnewbbox);
1594
1642
 
1595
1643
  if (im) {
1596
1644
  this._drawImage(im);
1597
1645
  }
1598
- } else {
1599
- // Draw
1600
- this._drawImage(this.layers[j]);
1601
1646
  }
1602
1647
  }
1603
1648
 
@@ -1687,6 +1732,7 @@ var WMCanvasBuffer = /*#__PURE__*/function () {
1687
1732
 
1688
1733
  var newLayer = {
1689
1734
  imageSource: imageSource,
1735
+ imageAge: getCurrentImageTime(),
1690
1736
  opacity: opacity,
1691
1737
  bbox: {
1692
1738
  left: bbox.left,
@@ -1907,8 +1953,9 @@ var WMJSAnimate = /*#__PURE__*/function () {
1907
1953
  for (var i = 0; i < this._map.animationList[nextStep].requests.length; i += 1) {
1908
1954
  var url = this._map.animationList[nextStep].requests[i].url;
1909
1955
  var image = getMapImageStore.getImageForSrc(url);
1956
+ /* Get a loaded image which has no error */
1910
1957
 
1911
- if (image && image.isLoaded()) {
1958
+ if (image && image.isLoaded() && !image.isLoading() && !image.hasError()) {
1912
1959
  numReady += 1;
1913
1960
  } else {
1914
1961
  /* Check if a similar image is available instead, then we can continue with the smoother animation */
@@ -1916,11 +1963,14 @@ var WMJSAnimate = /*#__PURE__*/function () {
1916
1963
 
1917
1964
  if (im) {
1918
1965
  numReady += 1;
1966
+ } else if (!(image && image.isLoading())) {
1967
+ /* No alternatives and current image is not loading, so lets continue the animation */
1968
+ numReady += 1;
1919
1969
  }
1920
1970
  }
1921
1971
  }
1922
1972
 
1923
- if (numReady === this._map.animationList[nextStep].requests.length) {
1973
+ if (numReady >= this._map.animationList[nextStep].requests.length) {
1924
1974
  continueAnimation = true;
1925
1975
  }
1926
1976
 
@@ -1974,9 +2024,11 @@ var WMJSAnimate = /*#__PURE__*/function () {
1974
2024
  this._map.setDimension(animationStep.name, animationStep.value, false);
1975
2025
 
1976
2026
  this._map.animationList[index].imagesInPrefetch = prefetch(this._map.animationList[index].requests);
1977
- getNumImagesLoading += this._map.animationList[index].imagesInPrefetch.length; // imageStore.getNumImagesLoading();
2027
+ getNumImagesLoading = this._imageStore.getNumImagesLoading();
1978
2028
 
1979
- if (getNumImagesLoading > maxSimultaneousLoads - 1) break;
2029
+ if (getNumImagesLoading > maxSimultaneousLoads - 1) {
2030
+ break;
2031
+ }
1980
2032
  }
1981
2033
  }
1982
2034
  }
@@ -2877,6 +2929,7 @@ var WMJSDimension = /*#__PURE__*/function () {
2877
2929
  this.initialize = this.initialize.bind(this);
2878
2930
  this.getValue = this.getValue.bind(this);
2879
2931
  this.setValue = this.setValue.bind(this);
2932
+ this.getValues = this.setValue.bind(this);
2880
2933
  this.setClosestValue = this.setClosestValue.bind(this);
2881
2934
  this.addTimeRangeDurationToValue = this.addTimeRangeDurationToValue.bind(this);
2882
2935
  this.setTimeRangeDuration = this.setTimeRangeDuration.bind(this);
@@ -2885,6 +2938,7 @@ var WMJSDimension = /*#__PURE__*/function () {
2885
2938
  this.get = this.get.bind(this);
2886
2939
  this.getFirstValue = this.getFirstValue.bind(this);
2887
2940
  this.getLastValue = this.getLastValue.bind(this);
2941
+ this.getDimInterval = this.getDimInterval.bind(this);
2888
2942
  this.getIndexForValue = this.getIndexForValue.bind(this);
2889
2943
  this.size = this.size.bind(this);
2890
2944
  this.clone = this.clone.bind(this);
@@ -3159,6 +3213,17 @@ var WMJSDimension = /*#__PURE__*/function () {
3159
3213
 
3160
3214
  this.currentValue = value;
3161
3215
  }
3216
+ /**
3217
+ * Returns values of the dimension, according to values defined in WMS specification, e.g. 2011-01-01T00:00:00Z/2012-01-01T00:00:00Z/P1M or list of values.
3218
+ * @returns
3219
+ */
3220
+
3221
+ }, {
3222
+ key: "getValues",
3223
+ value: function getValues() {
3224
+ this.initialize();
3225
+ return this.values;
3226
+ }
3162
3227
  }, {
3163
3228
  key: "setClosestValue",
3164
3229
  value: function setClosestValue() {
@@ -3301,6 +3366,17 @@ var WMJSDimension = /*#__PURE__*/function () {
3301
3366
  if (this._type === 'anyvalue') return this._allValues[index];
3302
3367
  return null;
3303
3368
  }
3369
+ /**
3370
+ * Hint about the timestep size / time resolution of this dimension.
3371
+ * @returns The dimTimeInterval
3372
+ */
3373
+
3374
+ }, {
3375
+ key: "getDimInterval",
3376
+ value: function getDimInterval() {
3377
+ this.initialize();
3378
+ return this.dimTimeInterval;
3379
+ }
3304
3380
  /**
3305
3381
  * Shorthand functionf or getValueForIndex
3306
3382
  */
@@ -7513,7 +7589,7 @@ rootNode, path) {
7513
7589
 
7514
7590
  if (layers[j].Layer) {
7515
7591
  nodeObject.children = [];
7516
- recursivelyFindLayer(toArray(layers[j].Layer), nodeObject.children, path + layers[j].Title.value);
7592
+ recursivelyFindLayer(toArray(layers[j].Layer), nodeObject.children, [].concat(_toConsumableArray(path), [layers[j].Title.value]));
7517
7593
  }
7518
7594
  } // Sort nodes alphabetically.
7519
7595
 
@@ -7841,7 +7917,7 @@ var WMJSService = /*#__PURE__*/function () {
7841
7917
  nodeStructure.text = I18n.unnamed_service.text;
7842
7918
  }
7843
7919
 
7844
- recursivelyFindLayer(WMSLayers, nodeStructure.children, '');
7920
+ recursivelyFindLayer(WMSLayers, nodeStructure.children, []);
7845
7921
  succes(nodeStructure);
7846
7922
  };
7847
7923
 
package/index.umd.js CHANGED
@@ -455,6 +455,14 @@
455
455
  * Copyright 2020 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
456
456
  * Copyright 2020 - Finnish Meteorological Institute (FMI)
457
457
  * */
458
+ /**
459
+ * Returns the current time in ms
460
+ * @returns the current time in ms
461
+ */
462
+
463
+ var getCurrentImageTime = function getCurrentImageTime() {
464
+ return new Date().getTime();
465
+ };
458
466
  /**
459
467
  * WMImage provides an API to the HTML image element. It is used for caching and easier access to images.
460
468
  */
@@ -476,6 +484,8 @@
476
484
  this._isLoaded = undefined;
477
485
  this._isLoading = undefined;
478
486
  this._hasError = undefined;
487
+ this._imageTimeStampAtError = getCurrentImageTime();
488
+ this._numFailedAttempts = 0;
479
489
  this.srcToLoad = src;
480
490
  this.loadEventCallback = callback;
481
491
  this.el = new Image();
@@ -494,6 +504,9 @@
494
504
  this.hasError = this.hasError.bind(this);
495
505
  this._load = this._load.bind(this);
496
506
  this.load = this.load.bind(this);
507
+ this.forceReload = this.forceReload.bind(this);
508
+ this.getLastErrorMSecondsAgo = this.getLastErrorMSecondsAgo.bind(this);
509
+ this.getNumFailedAttempts = this.getNumFailedAttempts.bind(this);
497
510
  this._loadEvent = this._loadEvent.bind(this);
498
511
  this.getWidth = this.getWidth.bind(this);
499
512
  this.getHeight = this.getHeight.bind(this);
@@ -504,6 +517,9 @@
504
517
  _this._loadEvent(false);
505
518
  });
506
519
  this.el.addEventListener('error', function () {
520
+ _this._imageTimeStampAtError = getCurrentImageTime();
521
+ _this._numFailedAttempts += 1;
522
+
507
523
  _this._loadEvent(true);
508
524
  });
509
525
 
@@ -521,6 +537,8 @@
521
537
  this._isLoaded = false;
522
538
  this._isLoading = false;
523
539
  this._hasError = false;
540
+ this._numFailedAttempts = 0;
541
+ this._imageTimeStampAtError = getCurrentImageTime();
524
542
  };
525
543
  /**
526
544
  * Returns true if the image has been loaded
@@ -539,6 +557,23 @@
539
557
  WMImage.prototype.isLoading = function () {
540
558
  return this._isLoading;
541
559
  };
560
+ /**
561
+ * Get the amount of milliseconds since the image experienced an image load.
562
+ * @returns milliseconds since the image had an error
563
+ */
564
+
565
+
566
+ WMImage.prototype.getLastErrorMSecondsAgo = function () {
567
+ return getCurrentImageTime() - this._imageTimeStampAtError;
568
+ };
569
+ /**
570
+ * @returns The number of failed attempts for this image
571
+ */
572
+
573
+
574
+ WMImage.prototype.getNumFailedAttempts = function () {
575
+ return this._numFailedAttempts;
576
+ };
542
577
  /**
543
578
  * Set source of image, but it will not load the image yet.
544
579
  * @param src URL of the image to load
@@ -563,6 +598,8 @@
563
598
  return;
564
599
  }
565
600
 
601
+ this._numFailedAttempts = 0;
602
+ this._imageTimeStampAtError = getCurrentImageTime();
566
603
  this._isLoaded = false;
567
604
  };
568
605
  /**
@@ -598,6 +635,13 @@
598
635
  this._load();
599
636
  };
600
637
 
638
+ WMImage.prototype.forceReload = function () {
639
+ this._isLoaded = false;
640
+ this._srcLoaded = undefined;
641
+
642
+ this._load();
643
+ };
644
+
601
645
  WMImage.prototype._getImageWithHeaders = function (url, headers) {
602
646
  var _this = this;
603
647
 
@@ -666,8 +710,12 @@
666
710
  var hostName = splittedHREF[0] + "//" + splittedHREF[1] + "/";
667
711
  this.srcToLoad = hostName + this.srcToLoad;
668
712
  }
713
+ /*
714
+ * If the image has already loaded this source succesfully (without error), simply trigger the loadevent.
715
+ */
669
716
 
670
- if (this.srcToLoad === this._srcLoaded) {
717
+
718
+ if (this.srcToLoad === this._srcLoaded && !this._hasError) {
671
719
  this._loadEvent(false);
672
720
 
673
721
  return;
@@ -1329,13 +1377,14 @@
1329
1377
  /* It is not in the list, so add it */
1330
1378
 
1331
1379
  if (imageIsAlreadyIndex === -1) {
1332
- sharedImagesList[sigImageUrl].push(newLayer);
1333
- }
1334
- /* Ensure that the oldest images are removed, keep a maximum of 10 images per signature url */
1380
+ /* Ensure that the oldest images are removed, keep a maximum of 10 images per signature url */
1381
+ while (sharedImagesList[sigImageUrl].length >= 10) {
1382
+ sharedImagesList[sigImageUrl].pop();
1383
+ }
1384
+ /* Add it to the beginning of the array for efficieny in searching at a later stage */
1335
1385
 
1336
1386
 
1337
- while (sharedImagesList[sigImageUrl].length > 10) {
1338
- sharedImagesList[sigImageUrl].splice(0, 1);
1387
+ sharedImagesList[sigImageUrl].unshift(newLayer);
1339
1388
  }
1340
1389
  };
1341
1390
  /**
@@ -1360,38 +1409,17 @@
1360
1409
  }
1361
1410
  };
1362
1411
  /**
1363
- * Algorithm two determine how much two bboxes are similar
1364
- * @param rect1
1365
- * @param rect2
1366
- * @returns
1367
- */
1368
-
1369
- var geClosestBBox = function geClosestBBox(rect1, rect2) {
1370
- var diffTLX = rect1.left - rect2.left;
1371
- var diffTLY = rect1.top - rect2.top;
1372
- var diffBRX = rect1.right - rect2.right;
1373
- var diffBRY = rect1.bottom - rect2.bottom;
1374
- return Math.sqrt(diffTLX * diffTLX + diffTLY * diffTLY) + Math.sqrt(diffBRX * diffBRX + diffBRY * diffBRY);
1375
- };
1376
- /**
1377
- * Sort the imageslist by overlapping area, highest area first
1412
+ * Sort the imageslist by imagedate, newewst image first.
1378
1413
  * @param imagesList
1379
- * @param bbox
1380
1414
  * @returns
1381
1415
  */
1382
1416
 
1383
- var sortByOverlappingArea = function sortByOverlappingArea(imagesList, bbox) {
1384
- var toSort = imagesList.map(function (im) {
1385
- return {
1386
- dist: geClosestBBox(im.bbox, bbox),
1387
- image: im
1388
- };
1389
- });
1390
- var sorted = toSort.sort(function (a, b) {
1391
- return a.dist > b.dist ? 1 : -1;
1417
+ var sortByImageDate = function sortByImageDate(imagesList) {
1418
+ var sorted = imagesList.sort(function (a, b) {
1419
+ return a.imageAge < b.imageAge ? 1 : -1;
1392
1420
  });
1393
1421
  return sorted.map(function (i) {
1394
- return i.image;
1422
+ return i;
1395
1423
  });
1396
1424
  };
1397
1425
  /**
@@ -1402,17 +1430,18 @@
1402
1430
  * @returns A canvasLayer, containing the new image source with its geo properties
1403
1431
  */
1404
1432
 
1405
- var getAlternativeImage = function getAlternativeImage(imageUrl, imageStore, bbox) {
1433
+ var getAlternativeImage = function getAlternativeImage(imageUrl, imageStore, // eslint-disable-next-line no-unused-vars
1434
+ _bbox) {
1406
1435
  var sigImageUrl = makeQueryStringWithoutGeoInfo(imageUrl);
1407
1436
  var imagesForUrl = sharedImagesList[sigImageUrl];
1408
1437
 
1409
1438
  if (imagesForUrl && imagesForUrl.length > 0) {
1410
- var sortedImagesForUrl = sortByOverlappingArea(imagesForUrl, bbox);
1411
- /* Find the first image in this list which is also loaded */
1439
+ var sortedImagesForUrl = sortByImageDate(imagesForUrl);
1440
+ /* Find the first image in this list which is also loaded and has no error */
1412
1441
 
1413
1442
  var index = sortedImagesForUrl.findIndex(function (altImage) {
1414
1443
  var cachedImage = imageStore.getImageForSrc(altImage.imageSource);
1415
- return cachedImage && cachedImage.isLoaded();
1444
+ return cachedImage && cachedImage.isLoaded() && !cachedImage.isLoading() && !cachedImage.hasError();
1416
1445
  });
1417
1446
  if (index !== -1) return sortedImagesForUrl[index];
1418
1447
  }
@@ -1573,16 +1602,29 @@
1573
1602
  for (var j = 0; j < this.layers.length; j += 1) {
1574
1603
  var imageToDisplay = this._imageStore.getImageForSrc(this.layers[j].imageSource);
1575
1604
 
1576
- if (!imageToDisplay || imageToDisplay.isLoaded() === false) {
1577
- /* Find closest image */
1605
+ if (imageToDisplay && imageToDisplay.isLoaded() && !imageToDisplay.isLoading() && !imageToDisplay.hasError()) {
1606
+ // Draw this image, it is loaded and OK
1607
+ this._drawImage(this.layers[j]);
1608
+ } else {
1609
+ /**
1610
+ * Check if this image has an error.
1611
+ * If the error has occured some time ago, and the amount of retries is low, just retry to load the image.
1612
+ */
1613
+ if (imageToDisplay.hasError()) {
1614
+ if (imageToDisplay.isLoading() === false && imageToDisplay.getLastErrorMSecondsAgo() > 5000) {
1615
+ if (imageToDisplay.getNumFailedAttempts() < 10) {
1616
+ imageToDisplay.forceReload();
1617
+ }
1618
+ }
1619
+ }
1620
+ /* Find closest alternative and display instead image */
1621
+
1622
+
1578
1623
  var im = getAlternativeImage(this.layers[j].imageSource, this._imageStore, this._currentnewbbox);
1579
1624
 
1580
1625
  if (im) {
1581
1626
  this._drawImage(im);
1582
1627
  }
1583
- } else {
1584
- // Draw
1585
- this._drawImage(this.layers[j]);
1586
1628
  }
1587
1629
  }
1588
1630
 
@@ -1669,6 +1711,7 @@
1669
1711
 
1670
1712
  var newLayer = {
1671
1713
  imageSource: imageSource,
1714
+ imageAge: getCurrentImageTime(),
1672
1715
  opacity: opacity,
1673
1716
  bbox: {
1674
1717
  left: bbox.left,
@@ -1897,8 +1940,9 @@
1897
1940
  for (var i = 0; i < this._map.animationList[nextStep].requests.length; i += 1) {
1898
1941
  var url = this._map.animationList[nextStep].requests[i].url;
1899
1942
  var image = getMapImageStore.getImageForSrc(url);
1943
+ /* Get a loaded image which has no error */
1900
1944
 
1901
- if (image && image.isLoaded()) {
1945
+ if (image && image.isLoaded() && !image.isLoading() && !image.hasError()) {
1902
1946
  numReady += 1;
1903
1947
  } else {
1904
1948
  /* Check if a similar image is available instead, then we can continue with the smoother animation */
@@ -1906,11 +1950,14 @@
1906
1950
 
1907
1951
  if (im) {
1908
1952
  numReady += 1;
1953
+ } else if (!(image && image.isLoading())) {
1954
+ /* No alternatives and current image is not loading, so lets continue the animation */
1955
+ numReady += 1;
1909
1956
  }
1910
1957
  }
1911
1958
  }
1912
1959
 
1913
- if (numReady === this._map.animationList[nextStep].requests.length) {
1960
+ if (numReady >= this._map.animationList[nextStep].requests.length) {
1914
1961
  continueAnimation = true;
1915
1962
  }
1916
1963
 
@@ -1963,9 +2010,11 @@
1963
2010
  this._map.setDimension(animationStep.name, animationStep.value, false);
1964
2011
 
1965
2012
  this._map.animationList[index].imagesInPrefetch = prefetch(this._map.animationList[index].requests);
1966
- getNumImagesLoading += this._map.animationList[index].imagesInPrefetch.length; // imageStore.getNumImagesLoading();
2013
+ getNumImagesLoading = this._imageStore.getNumImagesLoading();
1967
2014
 
1968
- if (getNumImagesLoading > maxSimultaneousLoads - 1) break;
2015
+ if (getNumImagesLoading > maxSimultaneousLoads - 1) {
2016
+ break;
2017
+ }
1969
2018
  }
1970
2019
  }
1971
2020
  }
@@ -2903,6 +2952,7 @@
2903
2952
  this.initialize = this.initialize.bind(this);
2904
2953
  this.getValue = this.getValue.bind(this);
2905
2954
  this.setValue = this.setValue.bind(this);
2955
+ this.getValues = this.setValue.bind(this);
2906
2956
  this.setClosestValue = this.setClosestValue.bind(this);
2907
2957
  this.addTimeRangeDurationToValue = this.addTimeRangeDurationToValue.bind(this);
2908
2958
  this.setTimeRangeDuration = this.setTimeRangeDuration.bind(this);
@@ -2911,6 +2961,7 @@
2911
2961
  this.get = this.get.bind(this);
2912
2962
  this.getFirstValue = this.getFirstValue.bind(this);
2913
2963
  this.getLastValue = this.getLastValue.bind(this);
2964
+ this.getDimInterval = this.getDimInterval.bind(this);
2914
2965
  this.getIndexForValue = this.getIndexForValue.bind(this);
2915
2966
  this.size = this.size.bind(this);
2916
2967
  this.clone = this.clone.bind(this);
@@ -3189,6 +3240,16 @@
3189
3240
 
3190
3241
  this.currentValue = value;
3191
3242
  };
3243
+ /**
3244
+ * Returns values of the dimension, according to values defined in WMS specification, e.g. 2011-01-01T00:00:00Z/2012-01-01T00:00:00Z/P1M or list of values.
3245
+ * @returns
3246
+ */
3247
+
3248
+
3249
+ WMJSDimension.prototype.getValues = function () {
3250
+ this.initialize();
3251
+ return this.values;
3252
+ };
3192
3253
 
3193
3254
  WMJSDimension.prototype.setClosestValue = function (newValue, evenWhenOutsideRange) {
3194
3255
  if (newValue === void 0) {
@@ -3335,6 +3396,16 @@
3335
3396
  if (this._type === 'anyvalue') return this._allValues[index];
3336
3397
  return null;
3337
3398
  };
3399
+ /**
3400
+ * Hint about the timestep size / time resolution of this dimension.
3401
+ * @returns The dimTimeInterval
3402
+ */
3403
+
3404
+
3405
+ WMJSDimension.prototype.getDimInterval = function () {
3406
+ this.initialize();
3407
+ return this.dimTimeInterval;
3408
+ };
3338
3409
  /**
3339
3410
  * Shorthand functionf or getValueForIndex
3340
3411
  */
@@ -7485,7 +7556,7 @@
7485
7556
 
7486
7557
  if (layers[j].Layer) {
7487
7558
  nodeObject.children = [];
7488
- recursivelyFindLayer(toArray(layers[j].Layer), nodeObject.children, path + layers[j].Title.value);
7559
+ recursivelyFindLayer(toArray(layers[j].Layer), nodeObject.children, __spreadArray(__spreadArray([], __read(path)), [layers[j].Title.value]));
7489
7560
  }
7490
7561
  } // Sort nodes alphabetically.
7491
7562
 
@@ -7805,7 +7876,7 @@
7805
7876
  nodeStructure.text = I18n.unnamed_service.text;
7806
7877
  }
7807
7878
 
7808
- recursivelyFindLayer(WMSLayers, nodeStructure.children, '');
7879
+ recursivelyFindLayer(WMSLayers, nodeStructure.children, []);
7809
7880
  succes(nodeStructure);
7810
7881
  };
7811
7882
 
@@ -18,6 +18,7 @@ interface CanvasBBOX {
18
18
  export interface CanvasGeoLayer {
19
19
  bbox: CanvasBBOX;
20
20
  opacity: number;
21
+ imageAge: number;
21
22
  imageSource: string;
22
23
  }
23
24
  /**
@@ -49,12 +50,11 @@ export declare const getSharedImagesList: () => Record<string, CanvasGeoLayer[]>
49
50
  */
50
51
  export declare const geClosestBBox: (rect1: CanvasBBOX, rect2: CanvasBBOX) => number;
51
52
  /**
52
- * Sort the imageslist by overlapping area, highest area first
53
+ * Sort the imageslist by imagedate, newewst image first.
53
54
  * @param imagesList
54
- * @param bbox
55
55
  * @returns
56
56
  */
57
- export declare const sortByOverlappingArea: (imagesList: CanvasGeoLayer[], bbox: CanvasBBOX) => CanvasGeoLayer[];
57
+ export declare const sortByImageDate: (imagesList: CanvasGeoLayer[]) => CanvasGeoLayer[];
58
58
  /**
59
59
  * Function to find the an alternative available image for an image url that is not yet loaded
60
60
  * @param imageUrl The image source / url to find an alternative for
@@ -62,7 +62,7 @@ export declare const sortByOverlappingArea: (imagesList: CanvasGeoLayer[], bbox:
62
62
  * @param bbox The boundingbox to search this image for
63
63
  * @returns A canvasLayer, containing the new image source with its geo properties
64
64
  */
65
- export declare const getAlternativeImage: (imageUrl: string, imageStore: WMImageStore, bbox: CanvasBBOX) => CanvasGeoLayer;
65
+ export declare const getAlternativeImage: (imageUrl: string, imageStore: WMImageStore, _bbox: CanvasBBOX) => CanvasGeoLayer;
66
66
  export default class WMCanvasBuffer {
67
67
  canvas: HTMLCanvasElement;
68
68
  _ctx: CanvasRenderingContext2D;
@@ -2,6 +2,11 @@ export interface WMImageOptions {
2
2
  randomizer?: boolean;
3
3
  headers: Headers[];
4
4
  }
5
+ /**
6
+ * Returns the current time in ms
7
+ * @returns the current time in ms
8
+ */
9
+ export declare const getCurrentImageTime: () => number;
5
10
  /**
6
11
  * WMImage provides an API to the HTML image element. It is used for caching and easier access to images.
7
12
  */
@@ -16,6 +21,8 @@ export default class WMImage {
16
21
  loadEventCallback: (image: WMImage) => void;
17
22
  el: HTMLImageElement;
18
23
  headers: Headers[];
24
+ _imageTimeStampAtError: number;
25
+ _numFailedAttempts: number;
19
26
  /**
20
27
  *
21
28
  * @param src Optionally set the source URL to load
@@ -32,6 +39,15 @@ export default class WMImage {
32
39
  * Returns true if the image is still loading
33
40
  */
34
41
  isLoading(): boolean;
42
+ /**
43
+ * Get the amount of milliseconds since the image experienced an image load.
44
+ * @returns milliseconds since the image had an error
45
+ */
46
+ getLastErrorMSecondsAgo(): number;
47
+ /**
48
+ * @returns The number of failed attempts for this image
49
+ */
50
+ getNumFailedAttempts(): number;
35
51
  /**
36
52
  * Set source of image, but it will not load the image yet.
37
53
  * @param src URL of the image to load
@@ -54,6 +70,7 @@ export default class WMImage {
54
70
  * Start loading the image
55
71
  */
56
72
  load(): void;
73
+ forceReload(): void;
57
74
  private _getImageWithHeaders;
58
75
  private _load;
59
76
  private _loadEvent;
@@ -1,3 +1,4 @@
1
+ import { DateInterval } from './WMTime';
1
2
  interface WMJSDimensionConfig {
2
3
  name?: string;
3
4
  units?: string;
@@ -24,15 +25,15 @@ export default class WMJSDimension {
24
25
  synced: boolean;
25
26
  used?: boolean;
26
27
  values?: string;
27
- timeRangeDuration?: any;
28
+ private timeRangeDuration?;
28
29
  private _initialized;
29
30
  private _timeRangeDurationDate;
30
31
  private _allDates;
31
32
  private _type;
32
33
  private _allValues;
33
- dimMinValue: string;
34
- dimMaxValue: string;
35
- dimTimeInterval: any;
34
+ private dimMinValue;
35
+ private dimMaxValue;
36
+ private dimTimeInterval;
36
37
  constructor(config?: WMJSDimensionConfig);
37
38
  generateAllValues(): number[];
38
39
  setTimeValuesForReferenceTime(referenceTimeValueToSet: string, referenceTimeDim: WMJSDimension): void;
@@ -49,6 +50,11 @@ export default class WMJSDimension {
49
50
  * @param forceValue When set to false,check if the given value is outside range, and do nothing if this is the case
50
51
  */
51
52
  setValue(value: string, forceValue?: boolean): void;
53
+ /**
54
+ * Returns values of the dimension, according to values defined in WMS specification, e.g. 2011-01-01T00:00:00Z/2012-01-01T00:00:00Z/P1M or list of values.
55
+ * @returns
56
+ */
57
+ getValues(): string;
52
58
  setClosestValue(newValue?: any, evenWhenOutsideRange?: boolean): void;
53
59
  addTimeRangeDurationToValue(value: string): string;
54
60
  setTimeRangeDuration(duration: string): void;
@@ -57,6 +63,11 @@ export default class WMJSDimension {
57
63
  * Get dimension value for specified index
58
64
  */
59
65
  getValueForIndex(index: number): string;
66
+ /**
67
+ * Hint about the timestep size / time resolution of this dimension.
68
+ * @returns The dimTimeInterval
69
+ */
70
+ getDimInterval(): DateInterval;
60
71
  /**
61
72
  * Shorthand functionf or getValueForIndex
62
73
  */
@@ -21,14 +21,14 @@ interface NodeObject {
21
21
  text: string;
22
22
  leaf: boolean;
23
23
  name?: string;
24
- path?: string;
24
+ path?: string[];
25
25
  children?: [];
26
26
  keywords?: string[];
27
27
  abstract?: string;
28
28
  styles?: Style[];
29
29
  }
30
30
  export declare const sortByKey: (array: NodeObject[], key: string) => NodeObject[];
31
- export declare const recursivelyFindLayer: (layers: any[], rootNode: any[], path: string) => void;
31
+ export declare const recursivelyFindLayer: (layers: any[], rootNode: any[], path: string[]) => void;
32
32
  /**
33
33
  * WMJSService Class
34
34
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/webmap",
3
- "version": "2.1.4",
3
+ "version": "2.2.0",
4
4
  "description": "GeoWeb webmap library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {