ol-stac 0.0.0 → 0.0.1

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.
Files changed (120) hide show
  1. package/README.md +1 -1
  2. package/events/ErrorEvent.d.ts +17 -0
  3. package/events/ErrorEvent.d.ts.map +1 -0
  4. package/{src/ol/events → events}/ErrorEvent.js +9 -11
  5. package/events/ErrorEvent.js.map +1 -0
  6. package/layer/STAC.d.ts +422 -0
  7. package/layer/STAC.d.ts.map +1 -0
  8. package/layer/STAC.js +698 -0
  9. package/layer/STAC.js.map +1 -0
  10. package/layer/stacUtil.d.ts +46 -0
  11. package/layer/stacUtil.d.ts.map +1 -0
  12. package/layer/stacUtil.js +154 -0
  13. package/layer/stacUtil.js.map +1 -0
  14. package/package.json +3 -85
  15. package/source/GeoTIFF2.d.ts +35 -0
  16. package/source/GeoTIFF2.d.ts.map +1 -0
  17. package/{src/ol/source → source}/GeoTIFF2.js +9 -16
  18. package/source/GeoTIFF2.js.map +1 -0
  19. package/.eslintignore +0 -2
  20. package/.github/workflows/deploy.yml +0 -67
  21. package/.github/workflows/publish.yml +0 -32
  22. package/.github/workflows/release.yml +0 -21
  23. package/.github/workflows/test.yml +0 -85
  24. package/CHANGELOG.md +0 -14
  25. package/DEVELOPING.md +0 -104
  26. package/config/jsdoc/api/conf.json +0 -38
  27. package/config/jsdoc/api/index.md +0 -1
  28. package/config/jsdoc/api/readme.md +0 -65
  29. package/config/jsdoc/api/template/README.md +0 -3
  30. package/config/jsdoc/api/template/publish.js +0 -743
  31. package/config/jsdoc/api/template/static/scripts/linenumber.js +0 -11
  32. package/config/jsdoc/api/template/static/scripts/main.js +0 -305
  33. package/config/jsdoc/api/template/static/scripts/prettify/Apache-License-2.0.txt +0 -202
  34. package/config/jsdoc/api/template/static/scripts/prettify/lang-css.js +0 -2
  35. package/config/jsdoc/api/template/static/scripts/prettify/prettify.js +0 -28
  36. package/config/jsdoc/api/template/static/styles/carbon.css +0 -65
  37. package/config/jsdoc/api/template/static/styles/jaguar.css +0 -512
  38. package/config/jsdoc/api/template/static/styles/prettify-jsdoc.css +0 -111
  39. package/config/jsdoc/api/template/static/styles/prettify-tomorrow.css +0 -132
  40. package/config/jsdoc/api/template/static/theme +0 -1
  41. package/config/jsdoc/api/template/tmpl/container.tmpl +0 -205
  42. package/config/jsdoc/api/template/tmpl/details.tmpl +0 -84
  43. package/config/jsdoc/api/template/tmpl/example.tmpl +0 -2
  44. package/config/jsdoc/api/template/tmpl/examples.tmpl +0 -16
  45. package/config/jsdoc/api/template/tmpl/exceptions.tmpl +0 -30
  46. package/config/jsdoc/api/template/tmpl/layout.tmpl +0 -92
  47. package/config/jsdoc/api/template/tmpl/mainpage.tmpl +0 -14
  48. package/config/jsdoc/api/template/tmpl/members.tmpl +0 -38
  49. package/config/jsdoc/api/template/tmpl/method.tmpl +0 -132
  50. package/config/jsdoc/api/template/tmpl/navigation.tmpl +0 -59
  51. package/config/jsdoc/api/template/tmpl/observables.tmpl +0 -39
  52. package/config/jsdoc/api/template/tmpl/params.tmpl +0 -109
  53. package/config/jsdoc/api/template/tmpl/properties.tmpl +0 -85
  54. package/config/jsdoc/api/template/tmpl/returns.tmpl +0 -72
  55. package/config/jsdoc/api/template/tmpl/source.tmpl +0 -8
  56. package/config/jsdoc/api/template/tmpl/stability.tmpl +0 -7
  57. package/config/jsdoc/api/template/tmpl/tutorial.tmpl +0 -19
  58. package/config/jsdoc/api/template/tmpl/type.tmpl +0 -7
  59. package/config/jsdoc/info/conf.json +0 -22
  60. package/config/jsdoc/info/publish.js +0 -175
  61. package/config/jsdoc/package.json +0 -4
  62. package/config/jsdoc/plugins/api.cjs +0 -181
  63. package/config/jsdoc/plugins/default-export.cjs +0 -35
  64. package/config/jsdoc/plugins/define-plugin.cjs +0 -33
  65. package/config/jsdoc/plugins/events.cjs +0 -39
  66. package/config/jsdoc/plugins/inline-options.cjs +0 -102
  67. package/config/jsdoc/plugins/markdown.cjs +0 -119
  68. package/config/jsdoc/plugins/observable.cjs +0 -69
  69. package/config/jsdoc/plugins/virtual-plugin.cjs +0 -16
  70. package/config/rollup-full-build.js +0 -24
  71. package/config/tsconfig-build.json +0 -25
  72. package/examples/.eslintrc +0 -29
  73. package/examples/index.html +0 -100
  74. package/examples/index.js +0 -109
  75. package/examples/planetary-computer.html +0 -14
  76. package/examples/planetary-computer.js +0 -53
  77. package/examples/resources/Jugl.js +0 -15
  78. package/examples/resources/common.js +0 -111
  79. package/examples/stac-collection-webmaplinks.html +0 -9
  80. package/examples/stac-collection-webmaplinks.js +0 -55
  81. package/examples/stac-item-from-object.html +0 -9
  82. package/examples/stac-item-from-object.js +0 -102
  83. package/examples/stac-item-tileserver.html +0 -9
  84. package/examples/stac-item-tileserver.js +0 -34
  85. package/examples/stac-item.html +0 -9
  86. package/examples/stac-item.js +0 -45
  87. package/examples/stac-itemcollection.html +0 -11
  88. package/examples/stac-itemcollection.js +0 -39
  89. package/examples/templates/example.html +0 -206
  90. package/examples/templates/readme.md +0 -3
  91. package/examples/webpack/config.mjs +0 -69
  92. package/examples/webpack/example-builder.js +0 -410
  93. package/site/build.js +0 -26
  94. package/site/layouts/default.hbs +0 -78
  95. package/site/src/doc/faq.md +0 -8
  96. package/site/src/doc/index.md +0 -22
  97. package/site/src/doc/quickstart.md +0 -121
  98. package/site/src/doc/tutorials/index.md +0 -8
  99. package/site/src/download/index.hbs +0 -62
  100. package/site/src/favicon.ico +0 -0
  101. package/site/src/index.hbs +0 -71
  102. package/site/src/theme/index.css +0 -26
  103. package/site/src/theme/site.css +0 -531
  104. package/src/ol/layer/STAC.js +0 -780
  105. package/src/ol/layer/stacUtil.js +0 -169
  106. package/tasks/.eslintrc +0 -5
  107. package/tasks/build-website.sh +0 -90
  108. package/tasks/create-release.js +0 -107
  109. package/tasks/generate-index.js +0 -125
  110. package/tasks/generate-info.js +0 -189
  111. package/tasks/get-latest-release.js +0 -36
  112. package/tasks/newest-tag.js +0 -52
  113. package/tasks/prepare-package.js +0 -46
  114. package/tasks/publish.sh +0 -90
  115. package/test/README.md +0 -56
  116. package/test/browser/.eslintrc +0 -14
  117. package/test/browser/karma.config.cjs +0 -94
  118. package/test/browser/spec/ol/layer/STAC.test.js +0 -18
  119. package/test/browser/test-extensions.js +0 -419
  120. package/tsconfig.json +0 -62
package/layer/STAC.js ADDED
@@ -0,0 +1,698 @@
1
+ /**
2
+ * @module ol/layer/STAC
3
+ */
4
+ import ErrorEvent from '../events/ErrorEvent.js';
5
+ import GeoJSON from 'ol/format/GeoJSON.js';
6
+ import GeoTIFF from '../source/GeoTIFF2.js';
7
+ import ImageLayer from 'ol/layer/Image.js';
8
+ import Layer from 'ol/layer/Layer.js';
9
+ import LayerGroup from 'ol/layer/Group.js';
10
+ import StaticImage from 'ol/source/ImageStatic.js';
11
+ import TileJSON from 'ol/source/TileJSON.js';
12
+ import TileLayer from 'ol/layer/Tile.js';
13
+ import VectorLayer from 'ol/layer/Vector.js';
14
+ import VectorSource from 'ol/source/Vector.js';
15
+ import WMS from 'ol/source/TileWMS.js';
16
+ import WMTS, { optionsFromCapabilities } from 'ol/source/WMTS.js';
17
+ import WebGLTileLayer from 'ol/layer/WebGLTile.js';
18
+ import XYZ from 'ol/source/XYZ.js';
19
+ import create, { Asset, STAC } from 'stac-js';
20
+ import { defaultBoundsStyle, defaultCollectionStyle, getBoundsStyle, getGeoTiffSourceInfoFromAsset, getProjection, getSpecificWebMapUrl, getWmtsCapabilities, } from './stacUtil.js';
21
+ import { toGeoJSON } from 'stac-js/src/geo.js';
22
+ import { transformExtent } from 'ol/proj.js';
23
+ /**
24
+ * @typedef {import("ol/extent.js").Extent} Extent
25
+ */
26
+ /**
27
+ * @typedef {import("../source/GeoTIFF2.js").Options2} GeoTIFFSourceOptions
28
+ */
29
+ /**
30
+ * @typedef {import("ol/source/ImageStatic.js").Options} ImageStaticSourceOptions
31
+ */
32
+ /**
33
+ * @typedef {import("stac-js").Link} Link
34
+ */
35
+ /**
36
+ * @typedef {import("stac-js").STACObject} STACObject
37
+ */
38
+ /**
39
+ * @typedef {import('ol/style.js').Style} Style
40
+ */
41
+ /**
42
+ * @typedef {import("ol/source/XYZ.js").Options} XYZSourceOptions
43
+ */
44
+ /**
45
+ * @typedef {Object} Options
46
+ * @property {string} [url] The STAC URL. Any of `url` and `data` must be provided.
47
+ * Can also be used as url for data, if it is absolute and doesn't contain a self link.
48
+ * @property {STAC|Asset|Object} [data] The STAC metadata. Any of `url` and `data` must be provided.
49
+ * `data` take precedence over `url`.
50
+ * @property {Array<string|Asset>|null} [assets=null] The selector for the assets to be rendered,
51
+ * only for STAC Items and Collections.
52
+ * This can be an array of strings corresponding to asset keys or Asset objects.
53
+ * null shows the default asset, an empty array shows no asset.
54
+ * @property {Array<number>} [bands] The (one-based) bands to show.
55
+ * @property {function(GeoTIFFSourceOptions, Asset):(GeoTIFFSourceOptions|Promise<GeoTIFFSourceOptions>)} [getGeoTIFFSourceOptions]
56
+ * Optional function that can be used to configure the underlying GeoTIFF sources. The function can do any additional work
57
+ * and return the completed options or a promise for the same. The function will be called with the current source options
58
+ * and the STAC Asset.
59
+ * @property {function(ImageStaticSourceOptions, (Asset|Link)):(ImageStaticSourceOptions|Promise<ImageStaticSourceOptions>)} [getImageStaticSourceOptions]
60
+ * Optional function that can be used to configure the underlying ImageStatic sources. The function can do any additional work
61
+ * and return the completed options or a promise for the same. The function will be called with the current source options
62
+ * and the STAC Asset or Link.
63
+ * @property {function(XYZSourceOptions, (Asset|Link)):(XYZSourceOptions|Promise<XYZSourceOptions>)} [getXYZSourceOptions]
64
+ * Optional function that can be used to configure the underlying XYZ sources that displays imagery. The function can do any
65
+ * additional work and return the completed options or a promise for the same. The function will be called with the current
66
+ * source options and the STAC Asset or Link.
67
+ * @property {boolean} [displayGeoTiffByDefault=false] Allow to choose non-cloud-optimized GeoTiffs as default image to show,
68
+ * which might not work well for larger files or larger amounts of files.
69
+ * @property {boolean} [displayPreview=false] Allow to display images that a browser can display (e.g. PNG, JPEG),
70
+ * usually assets with role `thumbnail` or the link with relation type `preview`.
71
+ * The previews are usually not covering the full extents and as such may be placed incorrectly on the map.
72
+ * For performance reasons, it is recommended to enable this option if you pass in STAC API Items.
73
+ * @property {boolean} [displayOverview=true] Allow to display COGs and, if `displayGeoTiffByDefault` is enabled, GeoTiffs,
74
+ * usually the assets with role `overview` or `visual`.
75
+ * @property {string|boolean} [displayWebMapLink=false] Allow to display a layer based on the information provided through the
76
+ * web map links extension. It is only used if no other data is shown. You can set a specific type of
77
+ * web map link (`tilejson`, `wms`, `wmts`, `xyz`), let OpenLayers choose (`true`) or disable the functionality (`false`).
78
+ * @property {Style} [boundsStyle] The style for the overall bounds / footprint.
79
+ * @property {Style} [collectionStyle] The style for individual items in a list of STAC Items or Collections.
80
+ * @property {null|string} [crossOrigin] For thumbnails: The `crossOrigin` attribute for loaded images / tiles.
81
+ * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
82
+ * @property {function(Asset):string|null} [buildTileUrlTemplate=null] A function that generates a URL template for a tile server (XYZ),
83
+ * which will be used instead of the client-side GeoTIFF rendering (except if `useTileLayerAsFallback` is `true`).
84
+ * @property {boolean} [useTileLayerAsFallback=false] Uses the given URL template only when the client-side GeoTIFF rendering fails.
85
+ * @property {number} [opacity=1] Opacity (0, 1).
86
+ * @property {boolean} [visible=true] Visibility.
87
+ * @property {Extent} [extent] The bounding extent for layer rendering. The layer will not be
88
+ * rendered outside of this extent.
89
+ * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers
90
+ * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed
91
+ * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()`
92
+ * method was used.
93
+ * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be
94
+ * visible.
95
+ * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
96
+ * be visible.
97
+ * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
98
+ * visible.
99
+ * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
100
+ * be visible.
101
+ */
102
+ /**
103
+ * @classdesc
104
+ * Renders STAC entities such as STAC Items, Collectons or lists of them as returned by APIs.
105
+ * The layers created by this LayerGroup all have a 'stac' value that can be retrieved using `layer.get('stac')`.
106
+ *
107
+ * @extends LayerGroup
108
+ * @fires sourceready
109
+ * @fires assetsready
110
+ * @fires ErorEvent#event:error
111
+ * @api
112
+ */
113
+ class STACLayer extends LayerGroup {
114
+ /**
115
+ * @param {Options} options Layer options.
116
+ */
117
+ constructor(options) {
118
+ const superOptions = {};
119
+ [
120
+ 'opacity',
121
+ 'visible',
122
+ 'zIndex',
123
+ 'minResolution',
124
+ 'maxResolution',
125
+ 'minZoom',
126
+ 'maxZoom',
127
+ ].forEach((key) => (superOptions[key] = options[key]));
128
+ super(superOptions);
129
+ /**
130
+ * @type {function(GeoTIFFSourceOptions, Asset):(GeoTIFFSourceOptions|Promise<GeoTIFFSourceOptions>)}
131
+ * @private
132
+ */
133
+ this.getGeoTIFFSourceOptions_ = options.getGeoTIFFSourceOptions;
134
+ /**
135
+ * @type {function(ImageStaticSourceOptions, (Asset|Link)):(ImageStaticSourceOptions|Promise<ImageStaticSourceOptions>)}
136
+ * @private
137
+ */
138
+ this.getImageStaticSourceOptions_ = options.getImageStaticSourceOptions;
139
+ /**
140
+ * @type {function(XYZSourceOptions, (Asset|Link)):(XYZSourceOptions|Promise<XYZSourceOptions>)}
141
+ * @private
142
+ */
143
+ this.getXYZSourceOptions_ = options.getXYZSourceOptions;
144
+ /**
145
+ * @type {STAC|Asset}
146
+ * @private
147
+ */
148
+ this.data_;
149
+ /**
150
+ * @type {Array<Asset> | null}
151
+ * @private
152
+ */
153
+ this.assets_ = null;
154
+ /**
155
+ * @type {Array<number>}
156
+ * @private
157
+ */
158
+ this.bands_ = [];
159
+ /**
160
+ * @type {string | null}
161
+ * @private
162
+ */
163
+ this.crossOrigin_ = options.crossOrigin || null;
164
+ /**
165
+ * @type {boolean}
166
+ * @private
167
+ */
168
+ this.displayGeoTiffByDefault_ = Boolean(options.displayGeoTiffByDefault);
169
+ /**
170
+ * @type {boolean}
171
+ * @private
172
+ */
173
+ this.displayPreview_ = Boolean(options.displayPreview);
174
+ /**
175
+ * @type {boolean}
176
+ * @private
177
+ */
178
+ this.displayOverview_ = options.displayOverview === false ? false : true;
179
+ /**
180
+ * @type {string|boolean}
181
+ */
182
+ this.displayWebMapLink_ = options.displayWebMapLink || false;
183
+ /**
184
+ * @type {function(Asset):string|null}
185
+ * @private
186
+ */
187
+ this.buildTileUrlTemplate_ = options.buildTileUrlTemplate || null;
188
+ /**
189
+ * @type {boolean}
190
+ * @private
191
+ */
192
+ this.useTileLayerAsFallback_ = options.useTileLayerAsFallback || false;
193
+ /**
194
+ * @type {Style}
195
+ * @private
196
+ */
197
+ this.boundsStyle_ = options.boundsStyle || defaultBoundsStyle;
198
+ /**
199
+ * @type {Style}
200
+ * @private
201
+ */
202
+ this.collectionStyle_ = options.collectionStyle || defaultCollectionStyle;
203
+ /**
204
+ * @type {VectorLayer|null}
205
+ * @private
206
+ */
207
+ this.boundsLayer_ = null;
208
+ if (options.data) {
209
+ try {
210
+ this.configure_(options.data, options.url, options.assets, options.bands);
211
+ }
212
+ catch (error) {
213
+ this.handleError_(error);
214
+ }
215
+ return;
216
+ }
217
+ if (!options.url) {
218
+ throw new Error('Either url or data must be provided');
219
+ }
220
+ fetch(options.url)
221
+ .then((response) => response.json())
222
+ .then((data) => this.configure_(data, options.url, options.assets, options.bands))
223
+ .catch((error) => this.handleError_(error));
224
+ }
225
+ /**
226
+ * Returns the vector layer that visualizes the bounds / footprint.
227
+ * @return {VectorLayer|null} The vector layer for the bounds
228
+ */
229
+ getBoundsLayer() {
230
+ return this.boundsLayer_;
231
+ }
232
+ /**
233
+ * @private
234
+ * @param {Error} error The error.
235
+ */
236
+ handleError_(error) {
237
+ /**
238
+ * Error event.
239
+ *
240
+ * @event ErorEvent#event:error
241
+ * @type {Object}
242
+ * @property {Error} error - Provides the original error.
243
+ */
244
+ this.dispatchEvent(new ErrorEvent(error));
245
+ }
246
+ /**
247
+ * @private
248
+ * @param {STAC|Asset|Object} data The STAC data.
249
+ * @param {string} url The url to the data.
250
+ * @param {Array<Asset|string> | null} assets The assets to show.
251
+ * @param {Array<number>} bands The (one-based) bands to show.
252
+ */
253
+ configure_(data, url = null, assets = null, bands = []) {
254
+ if (data instanceof Asset || data instanceof STAC) {
255
+ this.data_ = data;
256
+ }
257
+ else {
258
+ this.data_ = create(data);
259
+ }
260
+ if (url && url.includes('://')) {
261
+ this.data_.setAbsoluteUrl(url);
262
+ }
263
+ this.bands_ = bands;
264
+ this.boundsLayer_ = this.addFootprint_();
265
+ const updateBoundsStyle = () => {
266
+ if (this.boundsLayer_) {
267
+ this.boundsLayer_.setStyle(getBoundsStyle(this.boundsStyle_, this));
268
+ }
269
+ };
270
+ this.getLayers().on('add', updateBoundsStyle);
271
+ this.getLayers().on('remove', updateBoundsStyle);
272
+ this.setAssets(assets)
273
+ .then(() => {
274
+ /**
275
+ * Invoked once all assets are loaded and shown on the map.
276
+ *
277
+ * @event assetsready
278
+ */
279
+ return this.dispatchEvent('assetsready');
280
+ })
281
+ .catch((error) => this.handleError_(error));
282
+ /**
283
+ * Invoked once the source is ready.
284
+ * If you provide the data inline, the event is likely fired before you can
285
+ * attach a listener to it. So this only really helps if a url is provided.
286
+ *
287
+ * @event sourceready
288
+ */
289
+ this.dispatchEvent('sourceready');
290
+ }
291
+ /**
292
+ * @private
293
+ * @return {Promise} Resolves when complete.
294
+ */
295
+ async addApiCollection_() {
296
+ const promises = this.getData()
297
+ .getAll()
298
+ .map((obj) => {
299
+ const subgroup = new STACLayer({
300
+ data: obj,
301
+ crossOrigin: this.crossOrigin_,
302
+ boundsStyle: this.collectionStyle_,
303
+ displayGeoTiffByDefault: this.displayGeoTiffByDefault_,
304
+ displayOverview: this.displayOverview_,
305
+ displayPreview: this.displayPreview_,
306
+ });
307
+ this.addLayer_(subgroup);
308
+ return subgroup;
309
+ });
310
+ return await Promise.all(promises);
311
+ }
312
+ /**
313
+ * @private
314
+ * @return {Promise} Resolves when complete.
315
+ */
316
+ async addStacAssets_() {
317
+ let assets = this.getAssets();
318
+ if (assets === null) {
319
+ assets = [];
320
+ // No specific asset given by the user, visualize the default geotiff
321
+ const geotiff = this.getData().getDefaultGeoTIFF(true, !this.displayGeoTiffByDefault_);
322
+ if (geotiff) {
323
+ assets.push(geotiff);
324
+ }
325
+ else {
326
+ // This may return Links or Assets
327
+ const thumbnails = this.getData().getThumbnails();
328
+ if (thumbnails.length > 0) {
329
+ assets.push(thumbnails[0]);
330
+ }
331
+ }
332
+ }
333
+ const promises = assets.map((asset) => this.addImagery_(asset));
334
+ return await Promise.all(promises);
335
+ }
336
+ /**
337
+ * @private
338
+ * @param {Asset|Link} [ref] A STAC Link or Asset
339
+ * @return {Promise<Layer|undefined>} Resolves with a Layer or undefined when complete.
340
+ */
341
+ async addImagery_(ref) {
342
+ if (!ref) {
343
+ return;
344
+ }
345
+ if (ref.isGeoTIFF()) {
346
+ return await this.addGeoTiff_(ref);
347
+ }
348
+ if (ref.canBrowserDisplayImage()) {
349
+ return await this.addThumbnail_(ref);
350
+ }
351
+ }
352
+ /**
353
+ * @private
354
+ * @param {Asset|Link} [thumbnail] A STAC Link or Asset
355
+ * @return {Promise<ImageLayer|undefined>} Resolves with am ImageLayer or udnefined when complete.
356
+ */
357
+ async addThumbnail_(thumbnail) {
358
+ if (!this.displayPreview_) {
359
+ return;
360
+ }
361
+ /**
362
+ * @type {ImageStaticSourceOptions}
363
+ */
364
+ let options = {
365
+ url: thumbnail.getAbsoluteUrl(),
366
+ projection: await getProjection(thumbnail, 'EPSG:4326'),
367
+ imageExtent: thumbnail.getContext().getBoundingBox(),
368
+ crossOrigin: this.crossOrigin_,
369
+ };
370
+ if (this.getImageStaticSourceOptions_) {
371
+ options = await this.getImageStaticSourceOptions_(options, thumbnail);
372
+ }
373
+ const layer = new ImageLayer({
374
+ source: new StaticImage(options),
375
+ });
376
+ this.addLayer_(layer, thumbnail);
377
+ return layer;
378
+ }
379
+ /**
380
+ * Adds a layer for the web map links available in the STAC links.
381
+ * @return {Promise<Array<TileLayer>|undefined>} Resolves with a Layer or undefined when complete.
382
+ */
383
+ async addWebMapLinks_() {
384
+ const links = this.getWebMapLinks();
385
+ if (links.length > 0) {
386
+ return await this.addLayerForLink(links[0]);
387
+ }
388
+ }
389
+ /**
390
+ * Adds a layer for a link that implements the web-map-links extension.
391
+ * Supports: TileJSON, WMS, WMTS, XYZ
392
+ * @see https://github.com/stac-extensions/web-map-links
393
+ * @param {Link} link A web map link
394
+ * @return {Promise<Array<TileLayer>|undefined>} Resolves with a list of layers or undefined when complete.
395
+ */
396
+ async addLayerForLink(link) {
397
+ // Replace any occurances of {s} if possible, otherwise return
398
+ const url = getSpecificWebMapUrl(link);
399
+ if (!url) {
400
+ return;
401
+ }
402
+ const options = {
403
+ attributions: link.getMetadata('attribution') ||
404
+ this.data_.getMetadata('attribution'),
405
+ crossOrigin: this.crossOrigin_,
406
+ url,
407
+ };
408
+ const sources = [];
409
+ switch (link.rel) {
410
+ case 'tilejson':
411
+ sources.push(new TileJSON(options));
412
+ break;
413
+ case 'wms':
414
+ if (!Array.isArray(link['wms:layers'])) {
415
+ return;
416
+ }
417
+ const styles = link['wms:styles'] || '';
418
+ for (const layer of link['wms:layers']) {
419
+ const params = Object.assign({
420
+ LAYERS: layer,
421
+ STYLES: styles,
422
+ }, link['wms:dimensions']);
423
+ const wmsOptions = Object.assign({}, options, { params });
424
+ sources.push(new WMS(wmsOptions));
425
+ }
426
+ break;
427
+ case 'wmts':
428
+ const wmtsCapabilities = await getWmtsCapabilities(url);
429
+ if (!wmtsCapabilities) {
430
+ return;
431
+ }
432
+ const layers = Array.isArray(link['wmts:layer'])
433
+ ? link['wmts:layer']
434
+ : [link['wmts:layer']];
435
+ for (const layer of layers) {
436
+ const wmtsOptions = Object.assign({}, options, { layer });
437
+ sources.push(new WMTS(optionsFromCapabilities(wmtsCapabilities, wmtsOptions)));
438
+ }
439
+ break;
440
+ case 'xyz':
441
+ sources.push(new XYZ(options));
442
+ break;
443
+ default:
444
+ return;
445
+ }
446
+ return sources.map((source) => {
447
+ const layer = new TileLayer({
448
+ source,
449
+ });
450
+ this.addLayer_(layer, link);
451
+ return layer;
452
+ });
453
+ }
454
+ /**
455
+ * @private
456
+ * @param {Asset} [asset] A STAC Asset
457
+ * @return {Promise<Layer|undefined>} Resolves with a Layer or undefined when complete.
458
+ */
459
+ async addGeoTiff_(asset) {
460
+ if (!this.displayOverview_) {
461
+ return;
462
+ }
463
+ if (this.buildTileUrlTemplate_ && !this.useTileLayerAsFallback_) {
464
+ return await this.addTileLayerForImagery_(asset);
465
+ }
466
+ const sourceInfo = getGeoTiffSourceInfoFromAsset(asset, this.bands_);
467
+ /**
468
+ * @type {GeoTIFFSourceOptions}
469
+ */
470
+ let options = {
471
+ sources: [sourceInfo],
472
+ };
473
+ const projection = await getProjection(asset);
474
+ if (projection) {
475
+ options.projection = projection;
476
+ }
477
+ if (this.getGeoTIFFSourceOptions_) {
478
+ options = await this.getGeoTIFFSourceOptions_(options, asset);
479
+ }
480
+ const tileserverFallback = async (asset, layer) => {
481
+ if (layer) {
482
+ this.getLayers().remove(layer);
483
+ }
484
+ return await this.addTileLayerForImagery_(asset);
485
+ };
486
+ try {
487
+ const source = new GeoTIFF(options);
488
+ const layer = new WebGLTileLayer({ source });
489
+ if (this.useTileLayerAsFallback_) {
490
+ const errorFn = () => tileserverFallback(asset, layer);
491
+ source.on('error', errorFn);
492
+ source.on('tileloaderror', errorFn);
493
+ // see https://github.com/openlayers/openlayers/issues/14926
494
+ source.on('change', () => {
495
+ if (source.getState() === 'error') {
496
+ tileserverFallback(asset, layer);
497
+ }
498
+ });
499
+ layer.on('error', errorFn);
500
+ // Call this to ensure we can load the GeoTIFF, otherwise try fallback
501
+ await source.getView();
502
+ }
503
+ this.addLayer_(layer, asset);
504
+ return layer;
505
+ }
506
+ catch (error) {
507
+ if (this.useTileLayerAsFallback_) {
508
+ return await tileserverFallback(asset, null);
509
+ }
510
+ this.handleError_(error);
511
+ }
512
+ }
513
+ /**
514
+ * @private
515
+ * @param {Asset|Link} [data] A STAC Asset or Link
516
+ * @return {Promise<TileLayer>} Resolves with a TileLayer when complete.
517
+ */
518
+ async addTileLayerForImagery_(data) {
519
+ /**
520
+ * @type {XYZSourceOptions}
521
+ */
522
+ let options = {
523
+ crossOrigin: this.crossOrigin_,
524
+ url: this.buildTileUrlTemplate_(data),
525
+ };
526
+ if (this.getXYZSourceOptions_) {
527
+ options = await this.getXYZSourceOptions_(options, data);
528
+ }
529
+ const layer = new TileLayer({
530
+ source: new XYZ(options),
531
+ });
532
+ this.addLayer_(layer, data);
533
+ return layer;
534
+ }
535
+ /**
536
+ * @param {Layer|LayerGroup} [layer] A Layer to add to the LayerGroup
537
+ * @param {STACObject} [data] The STAC object, can be any class exposed by stac-js
538
+ * @param {number} [zIndex=0] The z-index for the layer
539
+ * @private
540
+ */
541
+ addLayer_(layer, data, zIndex = 0) {
542
+ layer.set('stac', data);
543
+ layer.setZIndex(zIndex);
544
+ this.getLayers().push(layer);
545
+ }
546
+ /**
547
+ * @private
548
+ * @return {VectorLayer|null} The vector layer showing the geometry/bbox.
549
+ */
550
+ addFootprint_() {
551
+ let geojson = null;
552
+ const data = this.getData();
553
+ if (data.isItemCollection() || data.isCollectionCollection()) {
554
+ geojson = toGeoJSON(data.getBoundingBox());
555
+ }
556
+ else {
557
+ geojson = data.toGeoJSON();
558
+ }
559
+ if (geojson) {
560
+ const format = new GeoJSON();
561
+ const source = new VectorSource({
562
+ format,
563
+ loader: (extent, resolution, projection) => {
564
+ const features = format.readFeatures(geojson, {
565
+ featureProjection: projection,
566
+ });
567
+ source.addFeatures(features);
568
+ },
569
+ });
570
+ const vectorLayer = new VectorLayer({
571
+ source,
572
+ style: getBoundsStyle(this.boundsStyle_, this),
573
+ });
574
+ vectorLayer.set('bounds', true);
575
+ this.addLayer_(vectorLayer, data, 1);
576
+ return vectorLayer;
577
+ }
578
+ return null;
579
+ }
580
+ /**
581
+ * @private
582
+ */
583
+ async updateLayers_() {
584
+ // Remove old layers
585
+ const oldLayers = this.getLayers();
586
+ for (let i = oldLayers.getLength() - 1; i >= 0; i--) {
587
+ const layer = oldLayers.item(i);
588
+ const stac = layer.get('stac');
589
+ if (stac && (stac.isLink() || stac.isAsset())) {
590
+ oldLayers.removeAt(i);
591
+ }
592
+ }
593
+ // Add new layers
594
+ const data = this.getData();
595
+ if (data.isItemCollection() || data.isCollectionCollection()) {
596
+ await this.addApiCollection_();
597
+ }
598
+ else if (data.isItem() || data.isCollection()) {
599
+ await this.addStacAssets_();
600
+ }
601
+ if (this.displayWebMapLink_ && this.hasOnlyBounds()) {
602
+ await this.addWebMapLinks_();
603
+ }
604
+ }
605
+ /**
606
+ * Indicates whether the LayerGroup shows only the bounds layer (i.e. no imagery/tile layers).
607
+ * @return {boolean} `true` if only the bounds layer is shown, `false` otherwise.
608
+ */
609
+ hasOnlyBounds() {
610
+ const boundsLayer = this.getBoundsLayer();
611
+ const imgLayer = this.getLayersArray().find((layer) => layer !== boundsLayer);
612
+ return typeof imgLayer === 'undefined';
613
+ }
614
+ /**
615
+ * Returns all potential web map links based on the given value for `displayWebMapLink`.
616
+ * @return {Array<Link>} An array of links.
617
+ */
618
+ getWebMapLinks() {
619
+ let types = ['xyz', 'tilejson', 'wmts', 'wms']; // This also defines the priority
620
+ if (typeof this.displayWebMapLink_ === 'string') {
621
+ types = [this.displayWebMapLink_];
622
+ }
623
+ const links = this.data_.getLinksWithRels(types);
624
+ links.sort((a, b) => {
625
+ const prioA = types.indexOf(a.rel);
626
+ const prioB = types.indexOf(b.rel);
627
+ return prioA - prioB;
628
+ });
629
+ return links;
630
+ }
631
+ /**
632
+ * Update the assets to be rendered.
633
+ * @param {Array<string|Asset>|null} assets The assets to show.
634
+ * @return {Promise} Resolves when all assets are rendered.
635
+ */
636
+ async setAssets(assets) {
637
+ if (Array.isArray(assets)) {
638
+ this.assets_ = assets.map((asset) => {
639
+ if (typeof asset === 'string') {
640
+ return this.getData().getAsset(asset);
641
+ }
642
+ if (!(asset instanceof Asset)) {
643
+ return new Asset(asset);
644
+ }
645
+ return asset;
646
+ });
647
+ }
648
+ else {
649
+ this.assets_ = null;
650
+ }
651
+ await this.updateLayers_();
652
+ }
653
+ /**
654
+ * Get the STAC object.
655
+ *
656
+ * @return {STAC|Asset} The STAC object.
657
+ */
658
+ getData() {
659
+ return this.data_;
660
+ }
661
+ /**
662
+ * Get the STAC assets shown.
663
+ *
664
+ * @return {Array<Asset>} The STAC assets.
665
+ */
666
+ getAssets() {
667
+ return this.assets_;
668
+ }
669
+ /**
670
+ * Get the extent of the layer.
671
+ *
672
+ * @return {Extent|undefined} The layer extent.
673
+ */
674
+ getExtent() {
675
+ const data = this.getData();
676
+ if (!data) {
677
+ return;
678
+ }
679
+ const layer = this.getLayers().item(0);
680
+ if (!layer || !(layer instanceof Layer)) {
681
+ return;
682
+ }
683
+ const map = layer.getMapInternal();
684
+ if (!map) {
685
+ return;
686
+ }
687
+ const view = map.getView();
688
+ if (!view) {
689
+ return;
690
+ }
691
+ const bbox = data.getBoundingBox();
692
+ if (bbox) {
693
+ return transformExtent(bbox, 'EPSG:4326', view.getProjection());
694
+ }
695
+ }
696
+ }
697
+ export default STACLayer;
698
+ //# sourceMappingURL=STAC.js.map