ol-stac 0.0.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.
Files changed (107) hide show
  1. package/.eslintignore +2 -0
  2. package/.github/workflows/deploy.yml +67 -0
  3. package/.github/workflows/publish.yml +32 -0
  4. package/.github/workflows/release.yml +21 -0
  5. package/.github/workflows/test.yml +85 -0
  6. package/CHANGELOG.md +14 -0
  7. package/DEVELOPING.md +104 -0
  8. package/LICENSE.md +201 -0
  9. package/README.md +43 -0
  10. package/config/jsdoc/api/conf.json +38 -0
  11. package/config/jsdoc/api/index.md +1 -0
  12. package/config/jsdoc/api/readme.md +65 -0
  13. package/config/jsdoc/api/template/README.md +3 -0
  14. package/config/jsdoc/api/template/publish.js +743 -0
  15. package/config/jsdoc/api/template/static/scripts/linenumber.js +11 -0
  16. package/config/jsdoc/api/template/static/scripts/main.js +305 -0
  17. package/config/jsdoc/api/template/static/scripts/prettify/Apache-License-2.0.txt +202 -0
  18. package/config/jsdoc/api/template/static/scripts/prettify/lang-css.js +2 -0
  19. package/config/jsdoc/api/template/static/scripts/prettify/prettify.js +28 -0
  20. package/config/jsdoc/api/template/static/styles/carbon.css +65 -0
  21. package/config/jsdoc/api/template/static/styles/jaguar.css +512 -0
  22. package/config/jsdoc/api/template/static/styles/prettify-jsdoc.css +111 -0
  23. package/config/jsdoc/api/template/static/styles/prettify-tomorrow.css +132 -0
  24. package/config/jsdoc/api/template/static/theme +1 -0
  25. package/config/jsdoc/api/template/tmpl/container.tmpl +205 -0
  26. package/config/jsdoc/api/template/tmpl/details.tmpl +84 -0
  27. package/config/jsdoc/api/template/tmpl/example.tmpl +2 -0
  28. package/config/jsdoc/api/template/tmpl/examples.tmpl +16 -0
  29. package/config/jsdoc/api/template/tmpl/exceptions.tmpl +30 -0
  30. package/config/jsdoc/api/template/tmpl/layout.tmpl +92 -0
  31. package/config/jsdoc/api/template/tmpl/mainpage.tmpl +14 -0
  32. package/config/jsdoc/api/template/tmpl/members.tmpl +38 -0
  33. package/config/jsdoc/api/template/tmpl/method.tmpl +132 -0
  34. package/config/jsdoc/api/template/tmpl/navigation.tmpl +59 -0
  35. package/config/jsdoc/api/template/tmpl/observables.tmpl +39 -0
  36. package/config/jsdoc/api/template/tmpl/params.tmpl +109 -0
  37. package/config/jsdoc/api/template/tmpl/properties.tmpl +85 -0
  38. package/config/jsdoc/api/template/tmpl/returns.tmpl +72 -0
  39. package/config/jsdoc/api/template/tmpl/source.tmpl +8 -0
  40. package/config/jsdoc/api/template/tmpl/stability.tmpl +7 -0
  41. package/config/jsdoc/api/template/tmpl/tutorial.tmpl +19 -0
  42. package/config/jsdoc/api/template/tmpl/type.tmpl +7 -0
  43. package/config/jsdoc/info/conf.json +22 -0
  44. package/config/jsdoc/info/publish.js +175 -0
  45. package/config/jsdoc/package.json +4 -0
  46. package/config/jsdoc/plugins/api.cjs +181 -0
  47. package/config/jsdoc/plugins/default-export.cjs +35 -0
  48. package/config/jsdoc/plugins/define-plugin.cjs +33 -0
  49. package/config/jsdoc/plugins/events.cjs +39 -0
  50. package/config/jsdoc/plugins/inline-options.cjs +102 -0
  51. package/config/jsdoc/plugins/markdown.cjs +119 -0
  52. package/config/jsdoc/plugins/observable.cjs +69 -0
  53. package/config/jsdoc/plugins/virtual-plugin.cjs +16 -0
  54. package/config/rollup-full-build.js +24 -0
  55. package/config/tsconfig-build.json +25 -0
  56. package/examples/.eslintrc +29 -0
  57. package/examples/index.html +100 -0
  58. package/examples/index.js +109 -0
  59. package/examples/planetary-computer.html +14 -0
  60. package/examples/planetary-computer.js +53 -0
  61. package/examples/resources/Jugl.js +15 -0
  62. package/examples/resources/common.js +111 -0
  63. package/examples/stac-collection-webmaplinks.html +9 -0
  64. package/examples/stac-collection-webmaplinks.js +55 -0
  65. package/examples/stac-item-from-object.html +9 -0
  66. package/examples/stac-item-from-object.js +102 -0
  67. package/examples/stac-item-tileserver.html +9 -0
  68. package/examples/stac-item-tileserver.js +34 -0
  69. package/examples/stac-item.html +9 -0
  70. package/examples/stac-item.js +45 -0
  71. package/examples/stac-itemcollection.html +11 -0
  72. package/examples/stac-itemcollection.js +39 -0
  73. package/examples/templates/example.html +206 -0
  74. package/examples/templates/readme.md +3 -0
  75. package/examples/webpack/config.mjs +69 -0
  76. package/examples/webpack/example-builder.js +410 -0
  77. package/package.json +107 -0
  78. package/site/build.js +26 -0
  79. package/site/layouts/default.hbs +78 -0
  80. package/site/src/doc/faq.md +8 -0
  81. package/site/src/doc/index.md +22 -0
  82. package/site/src/doc/quickstart.md +121 -0
  83. package/site/src/doc/tutorials/index.md +8 -0
  84. package/site/src/download/index.hbs +62 -0
  85. package/site/src/favicon.ico +0 -0
  86. package/site/src/index.hbs +71 -0
  87. package/site/src/theme/index.css +26 -0
  88. package/site/src/theme/site.css +531 -0
  89. package/src/ol/events/ErrorEvent.js +25 -0
  90. package/src/ol/layer/STAC.js +780 -0
  91. package/src/ol/layer/stacUtil.js +169 -0
  92. package/src/ol/source/GeoTIFF2.js +47 -0
  93. package/tasks/.eslintrc +5 -0
  94. package/tasks/build-website.sh +90 -0
  95. package/tasks/create-release.js +107 -0
  96. package/tasks/generate-index.js +125 -0
  97. package/tasks/generate-info.js +189 -0
  98. package/tasks/get-latest-release.js +36 -0
  99. package/tasks/newest-tag.js +52 -0
  100. package/tasks/prepare-package.js +46 -0
  101. package/tasks/publish.sh +90 -0
  102. package/test/README.md +56 -0
  103. package/test/browser/.eslintrc +14 -0
  104. package/test/browser/karma.config.cjs +94 -0
  105. package/test/browser/spec/ol/layer/STAC.test.js +18 -0
  106. package/test/browser/test-extensions.js +419 -0
  107. package/tsconfig.json +62 -0
@@ -0,0 +1,69 @@
1
+ /* eslint-disable import/no-commonjs */
2
+
3
+ const classes = {};
4
+ const observables = {};
5
+
6
+ exports.handlers = {
7
+ newDoclet: function (e) {
8
+ const doclet = e.doclet;
9
+ if (doclet.kind == 'class' && !(doclet.longname in classes)) {
10
+ classes[doclet.longname] = doclet;
11
+ }
12
+ },
13
+
14
+ parseComplete: function (e) {
15
+ const doclets = e.doclets;
16
+ let cls, doclet, event, i, ii, observable;
17
+ for (i = 0, ii = doclets.length - 1; i < ii; ++i) {
18
+ doclet = doclets[i];
19
+ cls = classes[doclet.longname.split('#')[0]];
20
+ if (typeof doclet.observable == 'string' && cls) {
21
+ let name = doclet.name.replace(/^[sg]et/, '');
22
+ name = name.substr(0, 1).toLowerCase() + name.substr(1);
23
+ const key = doclet.longname.split('#')[0] + '#' + name;
24
+ doclet.observable = key;
25
+ if (!observables[key]) {
26
+ observables[key] = {};
27
+ }
28
+ observable = observables[key];
29
+ observable.name = name;
30
+ observable.readonly =
31
+ typeof observable.readonly == 'boolean' ? observable.readonly : true;
32
+ if (doclet.name.startsWith('get')) {
33
+ observable.type = doclet.returns[0].type;
34
+ observable.description = doclet.returns[0].description;
35
+ } else if (doclet.name.startsWith('set')) {
36
+ observable.readonly = false;
37
+ }
38
+ if (doclet.stability) {
39
+ observable.stability = doclet.stability;
40
+ }
41
+ if (!cls.observables) {
42
+ cls.observables = [];
43
+ }
44
+ observable = observables[doclet.observable];
45
+ if (observable.type && !cls.observables.includes(observable)) {
46
+ cls.observables.push(observable);
47
+ }
48
+ if (!cls.fires) {
49
+ cls.fires = [];
50
+ }
51
+ event = 'module:ol/Object.ObjectEvent#event:change:' + name;
52
+ if (!cls.fires.includes(event)) {
53
+ cls.fires.push(event);
54
+ }
55
+ }
56
+ }
57
+ },
58
+ };
59
+
60
+ exports.defineTags = function (dictionary) {
61
+ dictionary.defineTag('observable', {
62
+ mustNotHaveValue: true,
63
+ canHaveType: false,
64
+ canHaveName: false,
65
+ onTagged: function (doclet, tag) {
66
+ doclet.observable = '';
67
+ },
68
+ });
69
+ };
@@ -0,0 +1,16 @@
1
+ /* eslint-disable import/no-commonjs */
2
+
3
+ /**
4
+ * Handle the interface and abstract annotations.
5
+ * @param {Object} dictionary The tag dictionary.
6
+ */
7
+ exports.defineTags = function (dictionary) {
8
+ const classTag = dictionary.lookUp('class');
9
+ dictionary.defineTag('interface', {
10
+ mustNotHaveValue: true,
11
+ onTagged: function (doclet, tag) {
12
+ classTag.onTagged.apply(this, arguments);
13
+ doclet.virtual = true;
14
+ },
15
+ });
16
+ };
@@ -0,0 +1,24 @@
1
+ import commonjs from '@rollup/plugin-commonjs';
2
+ import externalGlobals from 'rollup-plugin-external-globals';
3
+ import resolve from '@rollup/plugin-node-resolve';
4
+ import terser from '@rollup/plugin-terser';
5
+
6
+ export default {
7
+ input: 'build/index.js',
8
+ output: {
9
+ name: 'ol_stac',
10
+ format: 'iife',
11
+ exports: 'default',
12
+ file: 'build/full/ol-stac.js',
13
+ sourcemap: true,
14
+ },
15
+ plugins: [
16
+ resolve({moduleDirectories: ['build', 'node_modules']}),
17
+ commonjs(),
18
+ externalGlobals({
19
+ geotiff: 'GeoTIFF',
20
+ ol: 'ol',
21
+ }),
22
+ terser(),
23
+ ],
24
+ };
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ /* Basic Options */
4
+ "target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
5
+ "module": "es2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
6
+ "allowJs": true, /* Allow javascript files to be compiled. */
7
+ "sourceMap": true, /* Generates corresponding '.map' file. */
8
+ // "outFile": "./", /* Concatenate and emit output to single file. */
9
+ "outDir": "../build/ol", /* Redirect output structure to the directory. */
10
+ "importHelpers": false, /* Import emit helpers from 'tslib'. */
11
+ /* Strict Type-Checking Options */
12
+ "strict": false, /* Enable all strict type-checking options. */
13
+ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
14
+ "strictNullChecks": true, /* Enable strict null checks. */
15
+ /* Module Resolution Options */
16
+ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
17
+ "esModuleInterop": false, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
18
+ "inlineSources": false, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
19
+ "skipLibCheck": true
20
+ },
21
+ "include": [
22
+ "../build/ol/**/*.js"
23
+ ],
24
+ "exclude": []
25
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "globals": {
3
+ "$": false,
4
+ "arc": false,
5
+ "bootstrap": false,
6
+ "chroma": false,
7
+ "common": false,
8
+ "createMapboxStreetsV6Style": false,
9
+ "d3": false,
10
+ "geojsonvt": false,
11
+ "gifler": false,
12
+ "GyroNorm": false,
13
+ "html2canvas": false,
14
+ "jspdf": false,
15
+ "jsts": false,
16
+ "JSZip": false,
17
+ "mapboxgl": false,
18
+ "monotoneChainConvexHull": false,
19
+ "NumpyLoader": false,
20
+ "saveAs": false,
21
+ "toastr": false,
22
+ "topojson": false,
23
+ "topolis": false,
24
+ "turf": false
25
+ },
26
+ "rules": {
27
+ "no-unused-vars": [2, {"varsIgnorePattern": "^map"}]
28
+ }
29
+ }
@@ -0,0 +1,100 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
6
+ <title>OL STAC Examples</title>
7
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" crossorigin="anonymous">
8
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/fontawesome.min.css" crossorigin="anonymous">
9
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/solid.css" crossorigin="anonymous">
10
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/brands.css" crossorigin="anonymous">
11
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/ol/ol.css">
12
+ <link rel="stylesheet" type="text/css" href="/ol-stac/theme/site.css">
13
+ <style>
14
+ input.search-query {
15
+ color: var(--ol-foreground-color);
16
+ }
17
+ .example {
18
+ display: block;
19
+ padding: 0.65rem;
20
+ height: 140px;
21
+ margin: 0.65rem 0;
22
+ overflow: auto;
23
+ }
24
+ .example p.description {
25
+ font-size: smaller;
26
+ margin: 5px 0;
27
+ }
28
+ a.example {
29
+ text-decoration: none;
30
+ }
31
+ a.example:hover :first-child {
32
+ text-decoration: underline;
33
+ }
34
+ a.bg-light:focus,
35
+ a.bg-light:hover,
36
+ button.bg-light:focus,
37
+ button.bg-light:hover {
38
+ background-color: #f8f9fa !important;
39
+ }
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <header class="navbar navbar-expand-md navbar-dark mb-3 px-3 py-0 fixed-top" role="navigation">
44
+ <a class="navbar-brand" href="/">OL STAC</a>
45
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#olmenu" aria-controls="olmenu" aria-expanded="false" aria-label="Toggle navigation">
46
+ <span class="navbar-toggler-icon"></span>
47
+ </button>
48
+
49
+ <!-- menu items that get hidden below 768px width -->
50
+ <nav class="collapse navbar-collapse" id="olmenu">
51
+ <form role="search">
52
+ <div class="input-group">
53
+ <input name="q" type="search" id="keywords" class="form-control search-query" placeholder="Search" aria-label="Examples" aria-describedby="count" autocomplete="off" autofocus>
54
+ <span class="input-group-text text-white bg-transparent" id="count"></span>
55
+ </div>
56
+ </form>
57
+ <ul class="navbar-nav ms-auto">
58
+ <li class="nav-item dropdown">
59
+ <a class="nav-link dropdown-toggle" href="#" id="docdropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Docs</a>
60
+ <div class="dropdown-menu dropdown-menu-end mb-3" aria-labelledby="docdropdown">
61
+ <a class="dropdown-item" href="/ol-stac/doc/">Docs</a>
62
+ <div class="dropdown-divider"></div>
63
+ <a class="dropdown-item" href="/ol-stac/doc/quickstart.html"><i class="fa fa-check fa-fw me-2 fa-lg"></i>Quick Start</a>
64
+ <a class="dropdown-item" href="/ol-stac/doc/faq.html"><i class="fa fa-question fa-fw me-2 fa-lg"></i>FAQ</a>
65
+ <a class="dropdown-item" href="/ol-stac/doc/tutorials/"><i class="fa fa-book fa-fw me-2 fa-lg"></i>Tutorials</a>
66
+ </div>
67
+ </li>
68
+ <li class="nav-item active"><a class="nav-link" href="../examples/">Examples</a></li>
69
+ <li class="nav-item"><a class="nav-link" href="../apidoc/"><i class="fa fa-sitemap me-1"></i>API</a></li>
70
+ <li class="nav-item dropdown">
71
+ <a class="nav-link dropdown-toggle" href="#" id="codedropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Code</a>
72
+ <div class="dropdown-menu dropdown-menu-end mb-3" aria-labelledby="codedropdown">
73
+ <a class="dropdown-item" href="https://github.com/m-mohr/ol-stac"><i class="fab fa-github fa-fw me-2 fa-lg"></i>Repository</a>
74
+ <a class="dropdown-item" href="/ol-stac/download/"><i class="fa fa-download fa-fw me-2 fa-lg"></i>Download</a>
75
+ </div>
76
+ </li>
77
+ </ul>
78
+ </nav>
79
+ </header>
80
+
81
+ <div class="container-fluid">
82
+ <div id="examples"></div>
83
+ <div style="display: none;">
84
+ <div id="template" class="row mt-3">
85
+ <div class="col-md-4 col-sm-6" jugl:repeat="example examples">
86
+ <a jugl:attributes="href example.link" class="example bg-light border rounded">
87
+ <strong><span jugl:replace="example.title">title</span></strong><br>
88
+ <small jugl:content="'(' + example.link + ')'"></small>
89
+ <p class="description" jugl:content="example.shortdesc"></p>
90
+ </a>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </div>
95
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
96
+ <script type="text/javascript" src="resources/Jugl.js"></script>
97
+ <script type="text/javascript" src="examples-info.js"></script>
98
+ <script type="text/javascript" src="index.js"></script>
99
+ </body>
100
+ </html>
@@ -0,0 +1,109 @@
1
+ (function () {
2
+ 'use strict';
3
+ /* global info, jugl */
4
+
5
+ const template = new jugl.Template('template');
6
+ const target = document.getElementById('examples');
7
+
8
+ function listExamples(examples) {
9
+ target.innerHTML = '';
10
+ template.process({
11
+ context: {examples: examples},
12
+ clone: true,
13
+ parent: target,
14
+ });
15
+ document.getElementById('count').innerHTML = String(examples.length);
16
+ }
17
+
18
+ let timerId;
19
+ function inputChange() {
20
+ if (timerId) {
21
+ window.clearTimeout(timerId);
22
+ }
23
+ const text = this.value;
24
+ timerId = window.setTimeout(function () {
25
+ filterList(text);
26
+ }, 500);
27
+ }
28
+
29
+ function getMatchingExamples(text) {
30
+ text = text.trim();
31
+ if (text.length === 0) {
32
+ return info.examples;
33
+ }
34
+ const words = text.toLowerCase().split(/\W+/);
35
+ const scores = {};
36
+ const updateScores = function (dict, word) {
37
+ // eslint-disable-next-line prefer-const
38
+ for (let exIndex in dict) {
39
+ let exScore = scores[exIndex];
40
+ if (!exScore) {
41
+ exScore = {};
42
+ scores[exIndex] = exScore;
43
+ }
44
+ exScore[word] = (exScore[word] || 0) + dict[exIndex];
45
+ }
46
+ };
47
+ words.forEach(function (word) {
48
+ const dict = info.wordIndex[word];
49
+ if (dict) {
50
+ updateScores(dict, word);
51
+ } else {
52
+ const r = new RegExp(word);
53
+ // eslint-disable-next-line prefer-const
54
+ for (let idx in info.wordIndex) {
55
+ if (r.test(idx)) {
56
+ updateScores(info.wordIndex[idx], word);
57
+ }
58
+ }
59
+ }
60
+ });
61
+ const examples = [];
62
+ // eslint-disable-next-line prefer-const
63
+ for (let exIndex in scores) {
64
+ const ex = info.examples[exIndex];
65
+ ex.score = 0;
66
+ ex.words = 0;
67
+ // eslint-disable-next-line prefer-const
68
+ for (let word in scores[exIndex]) {
69
+ ex.score += scores[exIndex][word];
70
+ ex.words++;
71
+ }
72
+ examples.push(ex);
73
+ }
74
+ // sort examples, first by number of words matched, then
75
+ // by word frequency
76
+ examples.sort(function (a, b) {
77
+ return b.score - a.score || b.words - a.words;
78
+ });
79
+ return examples;
80
+ }
81
+
82
+ function filterList(text) {
83
+ const examples = getMatchingExamples(text);
84
+ listExamples(examples);
85
+ updateHistoryState(text);
86
+ }
87
+
88
+ function updateHistoryState(text) {
89
+ text = text.trim();
90
+ const params = new URLSearchParams(window.location.search);
91
+ if (text.length === 0) {
92
+ params.delete('q');
93
+ } else {
94
+ params.set('q', text);
95
+ }
96
+ let fullUrl = window.location.pathname;
97
+ if (params.toString().length !== 0) {
98
+ fullUrl += `?${params.toString()}`;
99
+ }
100
+ history.replaceState(null, '', fullUrl);
101
+ }
102
+
103
+ const params = new URLSearchParams(window.location.search);
104
+ const text = params.get('q') || '';
105
+ const input = document.getElementById('keywords');
106
+ input.addEventListener('input', inputChange);
107
+ input.value = text;
108
+ filterList(text);
109
+ })();
@@ -0,0 +1,14 @@
1
+ ---
2
+ layout: example.html
3
+ title: Planetary Computer
4
+ shortdesc: Rendering a STAC Item from Planetary Computer.
5
+ docs: >
6
+ This example uses the STAC layer to render an item from Planetary Computer.
7
+ Planetary Computer requres that asset URLs are signed with a token. The example
8
+ uses the `getGeoTIFFSourceOptions` callback to sign the asset URL.
9
+ tags: "stac, stac item, geotiff, cog"
10
+ cloak:
11
+ - key: get_your_own_D6rA4zTHduk6KOKTXzGB
12
+ value: <Your API key from https://www.maptiler.com/cloud/>
13
+ ---
14
+ <div id="map" class="map"></div>
@@ -0,0 +1,53 @@
1
+ import Map from 'ol/Map.js';
2
+ import OSM from 'ol/source/OSM.js';
3
+ import STAC from '../src/ol/layer/STAC.js';
4
+ import TileLayer from 'ol/layer/WebGLTile.js';
5
+ import View from 'ol/View.js';
6
+ import proj4 from 'proj4';
7
+ import {register} from 'ol/proj/proj4.js';
8
+
9
+ register(proj4); // required to support source reprojection
10
+
11
+ /**
12
+ * Get a Shared Access Signature Token to authorize asset requests.
13
+ * See https://planetarycomputer.microsoft.com/docs/concepts/sas/
14
+ * @param {string} href The unsigned URL.
15
+ * @return {Promise<string>} A promise for the signed URL.
16
+ */
17
+ async function sign(href) {
18
+ const params = new URLSearchParams({href});
19
+ const response = await fetch(
20
+ `https://planetarycomputer.microsoft.com/api/sas/v1/sign?${params}`
21
+ );
22
+ const body = await response.json();
23
+ return body.href;
24
+ }
25
+
26
+ const layer = new STAC({
27
+ url: 'https://planetarycomputer.microsoft.com/api/stac/v1/collections/sentinel-2-l2a/items/S2B_MSIL2A_20220909T185929_R013_T10TES_20220910T222807',
28
+ assets: ['visual'],
29
+ async getGeoTIFFSourceOptions(options) {
30
+ for (const source of options.sources) {
31
+ source.url = await sign(source.url);
32
+ }
33
+ return options;
34
+ },
35
+ });
36
+
37
+ const background = new TileLayer({
38
+ source: new OSM(),
39
+ });
40
+
41
+ const map = new Map({
42
+ target: 'map',
43
+ layers: [background, layer],
44
+ view: new View({
45
+ center: [0, 0],
46
+ zoom: 0,
47
+ }),
48
+ });
49
+
50
+ layer.on('sourceready', () => {
51
+ const view = map.getView();
52
+ view.fit(layer.getExtent());
53
+ });
@@ -0,0 +1,15 @@
1
+ /*
2
+ * Jugl.js -- JavaScript Template Library
3
+ *
4
+ * Copyright 2007-2010 Tim Schaub
5
+ * Released under the MIT license. Please see
6
+ * http://github.com/tschaub/jugl/blob/master/license.txt for the full license.
7
+ */
8
+ /*
9
+ * Jugl.js -- JavaScript Template Library
10
+ *
11
+ * Copyright 2007-2010 Tim Schaub
12
+ * Released under the MIT license. Please see
13
+ * http://github.com/tschaub/jugl/blob/master/license.txt for the full license.
14
+ */
15
+ (function(){var f={prefix:"jugl",namespaceURI:null,loadTemplate:function(h){var i=function(l){var m,k,n=!l.status||(l.status>=200&&l.status<300);if(n){try{m=l.responseXML;k=new e(m.documentElement)}catch(j){m=document.createElement("div");m.innerHTML=l.responseText;k=new e(m.firstChild)}if(h.callback){h.callback.call(h.scope,k)}}else{if(h.failure){h.failure.call(h.scope,l)}}};d(h.url,i)}};var g=function(h,j){h=h||{};j=j||{};for(var i in j){h[i]=j[i]}return h};var a=function(l,o){var m,n,k,j,h;if(typeof(l)==="string"){m=document.getElementById(l);if(!m){throw Error("Element id not found: "+l)}l=m}if(typeof(o)==="string"){m=document.getElementById(o);if(!m){throw Error("Element id not found: "+o)}o=m}if(o.namespaceURI&&o.xml){n=document.createElement("div");n.innerHTML=o.xml;k=n.childNodes;for(j=0,h=k.length;j<h;++j){l.appendChild(k[j])}}else{if(l.ownerDocument&&l.ownerDocument.importNode&&l.ownerDocument!==o.ownerDocument){o=l.ownerDocument.importNode(o,true)}l.appendChild(o)}return o};var d=function(h,k,i){var j;if(typeof XMLHttpRequest!=="undefined"){j=new XMLHttpRequest()}else{if(typeof ActiveXObject!=="undefined"){j=new ActiveXObject("Microsoft.XMLHTTP")}else{throw new Error("XMLHttpRequest not supported")}}j.open("GET",h);j.onreadystatechange=function(){if(j.readyState===4){k.call(i,j)}};j.send(null)};var b=function(h,i){this.template=h;this.node=i;this.scope={};this.scope.repeat={}};g(b.prototype,{clone:function(){var i=this.node.cloneNode(true);i.removeAttribute("id");var h=new b(this.template,i);g(h.scope,this.scope);return h},getAttribute:function(h){var j;if(this.node.nodeType===1){if(this.template.usingNS){j=this.node.getAttributeNodeNS(f.namespaceURI,h)}else{j=this.node.getAttributeNode(f.prefix+":"+h)}if(j&&!j.specified){j=false}}var i;if(j){i=new c(this,j,h)}else{i=j}return i},setAttribute:function(h,i){this.node.setAttribute(h,i)},removeAttributeNode:function(h){this.node.removeAttributeNode(h.node)},getChildNodes:function(){var k=this.node.childNodes.length;var j=new Array(k);var l;for(var h=0;h<k;++h){l=new b(this.template,this.node.childNodes[h]);l.scope=g({},this.scope);j[h]=l}return j},removeChildNodes:function(){while(this.node.hasChildNodes()){this.node.removeChild(this.node.firstChild)}},removeChild:function(h){this.node.removeChild(h.node);return node},removeSelf:function(){this.node.parentNode.removeChild(this.node)},importNode:function(h){if(this.node.ownerDocument&&this.node.ownerDocument.importNode){if(h.node.ownerDocument!==this.node.ownerDocument){h.node=this.node.ownerDocument.importNode(h.node,true)}}},appendChild:function(h){this.importNode(h);this.node.appendChild(h.node)},insertAfter:function(h){this.importNode(h);var j=this.node.parentNode;var i=this.node.nextSibling;if(i){j.insertBefore(h.node,i)}else{j.appendChild(h.node)}},insertBefore:function(h){this.importNode(h);var i=this.node.parentNode;i.insertBefore(h.node,this.node)},process:function(){var j;var r=true;var n=["define","condition","repeat"];for(var o=0,p=n.length;o<p;++o){j=this.getAttribute(n[o]);if(j){r=j.process();if(!r){return}}}var q=this.getAttribute("content");if(q){q.process()}else{var k=this.getAttribute("replace");if(k){k.process()}}var m=this.getAttribute("attributes");if(m){m.process()}if(!q&&!k){this.processChildNodes()}var h=this.getAttribute("omit-tag");if(h){h.process()}var l=this.getAttribute("reflow");if(l){l.process()}},processChildNodes:function(){var k=this.getChildNodes();for(var j=0,h=k.length;j<h;++j){k[j].process()}}});var e=function(h){h=h||{};if(typeof h==="string"||(h.nodeType===1)){h={node:h}}if(typeof(h.node)==="string"){h.node=document.getElementById(h.node);if(!h.node){throw Error("Element id not found: "+h.node)}}if(h.node){this.node=h.node;this.loaded=true}else{if(h.url){this.load({url:h.url,callback:h.callback,scope:h.scope})}}};g(e.prototype,{node:null,usingNS:false,xmldom:window.ActiveXObject?new ActiveXObject("Microsoft.XMLDOM"):null,trimSpace:(/^\s*(\w+)\s+(.*?)\s*$/),loaded:false,loading:false,process:function(h){var i,j;h=g({context:null,clone:false,string:false},h);this.usingNS=this.node.getAttributeNodeNS&&f.namespaceURI;i=new b(this,this.node);if(h.clone||h.string){i=i.clone()}if(h.context){i.scope=h.context}i.process();if(h.string){if(i.node.innerHTML){j=i.node.innerHTML}else{if(this.xmldom){j=i.node.xml}else{j=(new XMLSerializer).serializeToString(i.node)}}}else{j=i.node;if(h.parent){if(h.clone){j=a(h.parent,i.node)}else{this.appendTo(h.parent)}}}return j},load:function(j){if(typeof j==="string"){j={url:j}}j=j||{};this.loading=true;var h=function(k){this.node=k.node;this.loading=false;this.loaded=true;if(j.callback){j.callback.apply(j.scope,[k])}};var i;if(j.failure){i=(function(){return function(k){j.failure.call(j.scope,k)}})()}f.loadTemplate({url:j.url,callback:h,failure:i,scope:this})},appendTo:function(h){this.node=a(h,this.node);return this}});var c=function(h,j,i){this.element=h;this.node=j;this.type=i;this.nodeValue=j.nodeValue;this.nodeName=j.nodeName;this.template=h.template};g(c.prototype,{splitAttributeValue:function(i){i=(i!=null)?i:this.nodeValue;var h=this.template.trimSpace.exec(i);return h&&h.length===3&&[h[1],h[2]]},splitExpressionPrefix:function(){var h=this.splitAttributeValue();if(!h||(h[0]!="structure"&&h[0]!="text")){h=[null,this.nodeValue]}return h},getAttributeValues:function(){return this.nodeValue.replace(/[\t\n]/g,"").replace(/;\s*$/,"").replace(/;;/g,"\t").split(";").join("\n").replace(/\t/g,";").split(/\n/g)},removeSelf:function(){this.element.removeAttributeNode(this)},process:function(){return this.processAttribute[this.type].apply(this,[])},evalInScope:function(k){var i=this.element.scope;var h=[];var j=[];for(key in i){h.push(key);j.push(i[key])}var l=new Function(h.join(","),"return "+k);return l.apply({},j)},processAttribute:{define:function(){var l,k,j,h=this.getAttributeValues();for(k=0,j=h.length;k<j;++k){l=this.splitAttributeValue(h[k]);this.element.scope[l[0]]=this.evalInScope(l[1])}this.removeSelf();return true},condition:function(){var h=!!(this.evalInScope(this.nodeValue));this.removeSelf();if(!h){this.element.removeSelf()}return h},repeat:function(){var l=this.splitAttributeValue();var r=l[0];var o=this.evalInScope(l[1]);this.removeSelf();if(!(o instanceof Array)){var q=new Array();for(var j in o){q.push(j)}o=q}var m;var h=this.element;for(var n=0,k=o.length;n<k;++n){m=this.element.clone();m.scope[r]=o[n];m.scope.repeat[r]={index:n,number:n+1,even:!(n%2),odd:!!(n%2),start:(n===0),end:(n===k-1),length:k};h.insertAfter(m);m.process();h=m}this.element.removeSelf();return false},content:function(){var m=this.splitExpressionPrefix();var p=this.evalInScope(m[1]);this.removeSelf();if(m[0]==="structure"){try{this.element.node.innerHTML=p}catch(l){var h=document.createElement("div");h.innerHTML=p;if(this.element.node.xml&&this.template.xmldom){while(this.element.node.firstChild){this.element.node.removeChild(this.element.node.firstChild)}this.template.xmldom.loadXML(h.outerHTML);var k=this.template.xmldom.firstChild.childNodes;for(var n=0,o=k.length;n<o;++n){this.element.node.appendChild(k[n])}}else{this.element.node.innerHTML=h.innerHTML}}}else{var q;if(this.element.node.xml&&this.template.xmldom){q=this.template.xmldom.createTextNode(p)}else{q=document.createTextNode(p)}var j=new b(this.template,q);this.element.removeChildNodes();this.element.appendChild(j)}return true},replace:function(){var k=this.splitExpressionPrefix();var j=this.evalInScope(k[1]);this.removeSelf();if(k[0]==="structure"){var m=document.createElement("div");m.innerHTML=j;if(this.element.node.xml&&this.template.xmldom){this.template.xmldom.loadXML(m.outerHTML);m=this.template.xmldom.firstChild}while(m.firstChild){var l=m.removeChild(m.firstChild);if(this.element.node.ownerDocument&&this.element.node.ownerDocument.importNode){if(l.ownerDocument!=this.element.node.ownerDocument){l=this.element.node.ownerDocument.importNode(l,true)}}this.element.node.parentNode.insertBefore(l,this.element.node)}}else{var i;if(this.element.node.xml&&this.template.xmldom){i=this.template.xmldom.createTextNode(j)}else{i=document.createTextNode(j)}var h=new b(this.template,i);this.element.insertBefore(h)}this.element.removeSelf();return true},attributes:function(){var h=this.getAttributeValues();var n,k,m;for(var l=0,j=h.length;l<j;++l){n=this.splitAttributeValue(h[l]);k=n[0];m=this.evalInScope(n[1]);if(m!==false){this.element.setAttribute(k,m)}}this.removeSelf();return true},"omit-tag":function(){var l=((this.nodeValue==="")||!!(this.evalInScope(this.nodeValue)));this.removeSelf();if(l){var k=this.element.getChildNodes();for(var j=0,h=k.length;j<h;++j){this.element.insertBefore(k[j])}this.element.removeSelf()}},reflow:function(){var h=((this.nodeValue==="")||!!(this.evalInScope(this.nodeValue)));this.removeSelf();if(h){if(this.element.node.outerHTML){this.element.node.outerHTML=this.element.node.outerHTML}else{this.element.node.innerHTML=this.element.node.innerHTML}}}}});window.jugl=g(f,{Template:e})})();
@@ -0,0 +1,111 @@
1
+ (function() {
2
+ "use strict"
3
+ /* global LZString */
4
+
5
+ let lzStringPromise;
6
+ function loadLzString() {
7
+ if (!lzStringPromise) {
8
+ lzStringPromise = new Promise(function (resolve, reject) {
9
+ const script = document.createElement('script')
10
+ script.src = 'https://cdn.jsdelivr.net/npm/lz-string@1.4.4/libs/lz-string.min.js';
11
+ document.head.append(script);
12
+ script.addEventListener('load', resolve);
13
+ script.addEventListener('error', reject);
14
+ });
15
+ }
16
+ return lzStringPromise;
17
+ }
18
+
19
+ function compress(json) {
20
+ return LZString.compressToBase64(JSON.stringify(json))
21
+ .replace(/\+/g, '-')
22
+ .replace(/\//g, '_')
23
+ .replace(/=+$/, '');
24
+ }
25
+
26
+ function fetchResource(resource) {
27
+ return new Promise(function (resolve, reject) {
28
+ const isImage = /\.(png|jpe?g|gif|tiff?|svg|kmz)$/.test(resource);
29
+ if (isImage) {
30
+ resolve ({
31
+ isBinary: true,
32
+ content: new URL(resource, window.location.href).href
33
+ });
34
+ } else {
35
+ const xhr = new XMLHttpRequest();
36
+ xhr.open('GET', resource);
37
+ xhr.responseType = 'text';
38
+ xhr.addEventListener('load', function () {
39
+ resolve ({
40
+ content: xhr.response
41
+ });
42
+ });
43
+ xhr.addEventListener('error', reject);
44
+ xhr.send();
45
+ }
46
+ })
47
+ }
48
+
49
+ const codepenButton = document.getElementById('codepen-button');
50
+ if (codepenButton) {
51
+ const form = document.getElementById('codepen-form');
52
+ codepenButton.href = form.action;
53
+ codepenButton.addEventListener('click', function (event) {
54
+ event.preventDefault();
55
+ const html = document.getElementById('example-html-source').innerText;
56
+ const js = document.getElementById('example-js-source').innerText;
57
+ let pkgJson = document.getElementById('example-pkg-source').innerText;
58
+ pkgJson = JSON.parse(pkgJson);
59
+ pkgJson['devDependencies']['typescript'] = 'latest';
60
+ pkgJson = JSON.stringify(pkgJson, undefined, 2);
61
+
62
+ const unique = new Set();
63
+ const localResources = (js.match(/'(?:\.\/)?(?:data|resources)\/[^']*'/g) || [])
64
+ .map(function (f) {
65
+ return f.replace(/^'(?:\.\/)?|'$/g, '');
66
+ })
67
+ .filter(function (f) {
68
+ return unique.has(f) ? false : unique.add(f);
69
+ });
70
+
71
+ const promises = localResources.map(function (resource) {
72
+ return fetchResource(resource);
73
+ });
74
+ promises.push(loadLzString());
75
+
76
+ Promise.all(promises).then(
77
+ function (results) {
78
+ const files = {
79
+ 'index.html': {content: html},
80
+ 'package.json': {content: pkgJson},
81
+ 'sandbox.config.json': {content: '{"template": "parcel"}'},
82
+ '.babelrc': {content: '{}'},
83
+ '.prettierrc': {
84
+ content: JSON.stringify(
85
+ {
86
+ printWidth: 80,
87
+ tabWidth: 2,
88
+ useTabs: false,
89
+ semi: true,
90
+ singleQuote: true,
91
+ trailingComma: 'es5',
92
+ bracketSpacing: false,
93
+ jsxBracketSameLine: false,
94
+ fluid: false,
95
+ },
96
+ undefined,
97
+ 2
98
+ ),
99
+ },
100
+ };
101
+ for (let i = 0; i < localResources.length; i++) {
102
+ files[localResources[i]] = results[i];
103
+ }
104
+
105
+ form.parameters.value = compress({files: files});
106
+ form.submit();
107
+ }
108
+ );
109
+ });
110
+ }
111
+ })();
@@ -0,0 +1,9 @@
1
+ ---
2
+ layout: example.html
3
+ title: STAC Collection with Web Map Links
4
+ shortdesc: Rendering a STAC Collection with with a selection of web mapping services.
5
+ docs: >
6
+ Geometry and web map links from SpatioTemporal Asset Catalog (STAC) Collections can be rendered as layer group.
7
+ tags: "stac, stac collection, wms, wmts, xyz, tilejson, tilelayer, layergroup"
8
+ ---
9
+ <div id="map" class="map"></div>
@@ -0,0 +1,55 @@
1
+ import Map from 'ol/Map.js';
2
+ import OSM from 'ol/source/OSM.js';
3
+ import STAC from '../src/ol/layer/STAC.js';
4
+ import TileLayer from 'ol/layer/WebGLTile.js';
5
+ import View from 'ol/View.js';
6
+ import proj4 from 'proj4';
7
+ import {register} from 'ol/proj/proj4.js';
8
+
9
+ register(proj4); // required to support source reprojection
10
+
11
+ const layer = new STAC({
12
+ displayWebMapLink: true,
13
+ data: {
14
+ 'stac_version': '1.0.0',
15
+ 'stac_extensions': [
16
+ 'https://stac-extensions.github.io/web-map-links/v1.1.0/schema.json',
17
+ ],
18
+ 'type': 'Collection',
19
+ 'id': 'averaged_PM10',
20
+ 'description': 'Particulate matter 10µm',
21
+ 'license': 'CC-BY-4.0',
22
+ 'attribution':
23
+ 'Copyright "© 2023 <a href="www.ecmwf.int">European Centre for Medium-Range Weather Forecasts (ECMWF)</a>',
24
+ 'extent': {
25
+ 'spatial': {
26
+ 'bbox': [[-25, 30, 45, 71]],
27
+ },
28
+ 'temporal': {
29
+ 'interval': [['2022-09-22T00:00:00Z', '2023-07-31T00:00:00Z']],
30
+ },
31
+ },
32
+ 'links': [
33
+ {
34
+ 'href': 'https://eccharts.ecmwf.int/wms/?token=public',
35
+ 'rel': 'wms',
36
+ 'wms:layers': ['composition_europe_pm10_analysis_surface'],
37
+ },
38
+ ],
39
+ },
40
+ });
41
+
42
+ const background = new TileLayer({
43
+ source: new OSM(),
44
+ });
45
+
46
+ const map = new Map({
47
+ target: 'map',
48
+ layers: [background, layer],
49
+ view: new View({
50
+ center: [0, 0],
51
+ zoom: 0,
52
+ }),
53
+ });
54
+ const view = map.getView();
55
+ view.fit(layer.getExtent());
@@ -0,0 +1,9 @@
1
+ ---
2
+ layout: example.html
3
+ title: STAC Item from an object
4
+ shortdesc: Rendering a STAC Item as a layer that is provided as a JS object.
5
+ docs: >
6
+ Geometry and Assets from SpatioTemporal Asset Catalog (STAC) Items can be rendered as layer group.
7
+ tags: "stac, stac item, geotiff, cog, layergroup"
8
+ ---
9
+ <div id="map" class="map"></div>