ogcopenapis 0.0.12 → 1.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.
- package/LICENSE +20 -20
- package/README.md +310 -72
- package/lib/OgcOpenApiCrsTools.d.ts +10 -9
- package/lib/OgcOpenApiCrsTools.d.ts.map +1 -0
- package/lib/OgcOpenApiCrsTools.js +40 -39
- package/lib/OgcOpenApiCrsTools.js.map +1 -0
- package/lib/OgcOpenApiFeatureStore.d.ts +94 -93
- package/lib/OgcOpenApiFeatureStore.d.ts.map +1 -0
- package/lib/OgcOpenApiFeatureStore.js +200 -244
- package/lib/OgcOpenApiFeatureStore.js.map +1 -0
- package/lib/OgcOpenApiFetchTools.d.ts +37 -30
- package/lib/OgcOpenApiFetchTools.d.ts.map +1 -0
- package/lib/OgcOpenApiFetchTools.js +68 -50
- package/lib/OgcOpenApiFetchTools.js.map +1 -0
- package/lib/OgcOpenApiGetCapabilities.d.ts +209 -112
- package/lib/OgcOpenApiGetCapabilities.d.ts.map +1 -0
- package/lib/OgcOpenApiGetCapabilities.js +424 -277
- package/lib/OgcOpenApiGetCapabilities.js.map +1 -0
- package/lib/OgcOpenApiMapsModel.d.ts +41 -36
- package/lib/OgcOpenApiMapsModel.d.ts.map +1 -0
- package/lib/OgcOpenApiMapsModel.js +88 -75
- package/lib/OgcOpenApiMapsModel.js.map +1 -0
- package/lib/OgcOpenApiMvtTools.d.ts +12 -0
- package/lib/OgcOpenApiMvtTools.d.ts.map +1 -0
- package/lib/OgcOpenApiMvtTools.js +100 -0
- package/lib/OgcOpenApiMvtTools.js.map +1 -0
- package/lib/OgcOpenApiStyleTools.d.ts +51 -0
- package/lib/OgcOpenApiStyleTools.d.ts.map +1 -0
- package/lib/OgcOpenApiStyleTools.js +155 -0
- package/lib/OgcOpenApiStyleTools.js.map +1 -0
- package/lib/OgcOpenApiTileMatrixTools.d.ts +41 -0
- package/lib/OgcOpenApiTileMatrixTools.d.ts.map +1 -0
- package/lib/OgcOpenApiTileMatrixTools.js +88 -0
- package/lib/OgcOpenApiTileMatrixTools.js.map +1 -0
- package/lib/OgcOpenApiTilesModel.d.ts +56 -31
- package/lib/OgcOpenApiTilesModel.d.ts.map +1 -0
- package/lib/OgcOpenApiTilesModel.js +167 -128
- package/lib/OgcOpenApiTilesModel.js.map +1 -0
- package/lib/OgcOpenApiVectorTilesModel.d.ts +39 -0
- package/lib/OgcOpenApiVectorTilesModel.d.ts.map +1 -0
- package/lib/OgcOpenApiVectorTilesModel.js +122 -0
- package/lib/OgcOpenApiVectorTilesModel.js.map +1 -0
- package/lib/OgcOpenApiWmtsTools.d.ts +30 -0
- package/lib/OgcOpenApiWmtsTools.d.ts.map +1 -0
- package/lib/OgcOpenApiWmtsTools.js +89 -0
- package/lib/OgcOpenApiWmtsTools.js.map +1 -0
- package/package.json +56 -27
- package/src/OgcOpenApiCrsTools.ts +40 -0
- package/src/OgcOpenApiFeatureStore.ts +296 -0
- package/src/OgcOpenApiFetchTools.ts +84 -0
- package/src/OgcOpenApiGetCapabilities.ts +641 -0
- package/src/OgcOpenApiMapsModel.ts +128 -0
- package/src/OgcOpenApiMvtTools.ts +104 -0
- package/src/OgcOpenApiStyleTools.ts +187 -0
- package/src/OgcOpenApiTileMatrixTools.ts +111 -0
- package/src/OgcOpenApiTilesModel.ts +214 -0
- package/src/OgcOpenApiVectorTilesModel.ts +141 -0
- package/src/OgcOpenApiWmtsTools.ts +114 -0
- package/lib/OgcOpenApiGetCollectionTiles.d.ts +0 -7
- package/lib/OgcOpenApiGetCollectionTiles.js +0 -7
|
@@ -1,277 +1,424 @@
|
|
|
1
|
-
import { OgcOpenApiFetchTools } from "./OgcOpenApiFetchTools";
|
|
2
|
-
const SCALE_DENOMINATOR_TOLERANCE = 1e-8;
|
|
3
|
-
export var CollectionLinkType;
|
|
4
|
-
(function (CollectionLinkType) {
|
|
5
|
-
CollectionLinkType["Items"] = "items";
|
|
6
|
-
CollectionLinkType["Styles"] = "styles";
|
|
7
|
-
CollectionLinkType["Map"] = "map";
|
|
8
|
-
CollectionLinkType["Tiles"] = "tiles";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
[CollectionLinkType.
|
|
13
|
-
[CollectionLinkType.
|
|
14
|
-
[CollectionLinkType.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
1
|
+
import { OgcOpenApiFetchTools } from "./OgcOpenApiFetchTools.js";
|
|
2
|
+
const SCALE_DENOMINATOR_TOLERANCE = 1e-8;
|
|
3
|
+
export var CollectionLinkType;
|
|
4
|
+
(function (CollectionLinkType) {
|
|
5
|
+
CollectionLinkType["Items"] = "items";
|
|
6
|
+
CollectionLinkType["Styles"] = "styles";
|
|
7
|
+
CollectionLinkType["Map"] = "map";
|
|
8
|
+
CollectionLinkType["Tiles"] = "tiles";
|
|
9
|
+
CollectionLinkType["VectorTiles"] = "vectorTiles";
|
|
10
|
+
})(CollectionLinkType || (CollectionLinkType = {}));
|
|
11
|
+
const CollectionLinkTypeAlternatives = {
|
|
12
|
+
[CollectionLinkType.Items]: ["items", "item"],
|
|
13
|
+
[CollectionLinkType.Styles]: ["http://www.opengis.net/def/rel/ogc/1.0/styles", "styles"],
|
|
14
|
+
[CollectionLinkType.Map]: ["http://www.opengis.net/def/rel/ogc/1.0/map", "map"],
|
|
15
|
+
[CollectionLinkType.Tiles]: ["http://www.opengis.net/def/rel/ogc/1.0/tilesets-map", "tilesets-map"],
|
|
16
|
+
[CollectionLinkType.VectorTiles]: ["http://www.opengis.net/def/rel/ogc/1.0/tilesets-vector", "tilesets-vector"],
|
|
17
|
+
};
|
|
18
|
+
// OGC API link relations are given in full or, by older servers, short: tiling-scheme or http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme
|
|
19
|
+
const OGC_REL = "http://www.opengis.net/def/rel/ogc/1.0/";
|
|
20
|
+
const isRel = (link, rel) => link.rel === OGC_REL + rel || link.rel === rel;
|
|
21
|
+
const CollectionLinkTypeDefaultFormat = {
|
|
22
|
+
[CollectionLinkType.Map]: "image/png",
|
|
23
|
+
[CollectionLinkType.Tiles]: "image/png",
|
|
24
|
+
[CollectionLinkType.VectorTiles]: "application/vnd.mapbox-vector-tile",
|
|
25
|
+
};
|
|
26
|
+
export class OgcOpenApiGetCapabilities {
|
|
27
|
+
static fromURL(inputRequest, fromUrlOptions) {
|
|
28
|
+
const options = fromUrlOptions ? fromUrlOptions : {};
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const baseUrl = OgcOpenApiFetchTools.cleanUrl(inputRequest);
|
|
31
|
+
const requestUrl = OgcOpenApiFetchTools.cleanUrl(inputRequest);
|
|
32
|
+
const serverOptions = OgcOpenApiFetchTools.createFetchOptions({ originalUrl: requestUrl, proxify: options?.proxify });
|
|
33
|
+
OgcOpenApiFetchTools.fetch(requestUrl, {
|
|
34
|
+
method: 'GET',
|
|
35
|
+
credentials: options?.credentials ? "same-origin" : "omit",
|
|
36
|
+
headers: options ? options.requestHeaders : {},
|
|
37
|
+
}, serverOptions).then((response) => {
|
|
38
|
+
if (response.status === 200) {
|
|
39
|
+
response.json().then((jsonObject) => {
|
|
40
|
+
if (!jsonObject.links) {
|
|
41
|
+
reject("Invalid format: (property 'links' is missing)");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let linkToData = jsonObject.links.find((link) => link.rel === 'data' && link.type === 'application/json');
|
|
45
|
+
if (!linkToData) {
|
|
46
|
+
linkToData = jsonObject.links.find((link) => link.rel === 'data');
|
|
47
|
+
}
|
|
48
|
+
const linkToApi = jsonObject.links.find((link) => {
|
|
49
|
+
return ((link.rel === 'service-desc' || link.rel === 'service') &&
|
|
50
|
+
link.type.indexOf('openapi+json') > -1);
|
|
51
|
+
});
|
|
52
|
+
const tilingSchemes = jsonObject.links.filter((link) => isRel(link, 'tiling-schemes'));
|
|
53
|
+
const linkToTileMatrixSets = tilingSchemes.find((link) => link.type === 'application/json') || tilingSchemes.find((link) => !link.type);
|
|
54
|
+
// The links of the landing page are relative to it, the links of the collections to /collections
|
|
55
|
+
const resolveLink = (link, documentUrl) => ({ ...link, href: OgcOpenApiFetchTools.resolveUrl(link.href, documentUrl, serverOptions) });
|
|
56
|
+
const promiseArray = [];
|
|
57
|
+
if (linkToData) {
|
|
58
|
+
const collectionsLink = resolveLink(linkToData, requestUrl);
|
|
59
|
+
const collectionsPromise = OgcOpenApiGetCapabilities.fetchLinkContentAsJSON(collectionsLink, { credentials: options.credentials, requestHeaders: options.requestHeaders }, serverOptions);
|
|
60
|
+
promiseArray.push(collectionsPromise);
|
|
61
|
+
if (linkToApi) {
|
|
62
|
+
const apiPromise = OgcOpenApiGetCapabilities.fetchLinkContentAsJSON(resolveLink(linkToApi, requestUrl), { credentials: options.credentials, requestHeaders: options.requestHeaders }, serverOptions);
|
|
63
|
+
promiseArray.push(apiPromise);
|
|
64
|
+
}
|
|
65
|
+
Promise.all(promiseArray).then((responses) => {
|
|
66
|
+
const responseDataLink = responses[0];
|
|
67
|
+
const responseOpenApi = responses.length >= 1 ? responses[1] : undefined;
|
|
68
|
+
const crsArray = typeof responseDataLink.crs !== "undefined" ? { crs: responseDataLink.crs } : {};
|
|
69
|
+
const foundCollections = responseDataLink.collections.filter(c => options && options.filterCollectionsByLinkType ?
|
|
70
|
+
OgcOpenApiGetCapabilities.filterCollectionLinks(c.links, options.filterCollectionsByLinkType).length > 0 : true)
|
|
71
|
+
.map((collection) => {
|
|
72
|
+
const name = typeof collection.id !== 'undefined'
|
|
73
|
+
? collection.id
|
|
74
|
+
: collection.name;
|
|
75
|
+
const collectionCrsObject = {};
|
|
76
|
+
if (typeof collection.crs !== "undefined")
|
|
77
|
+
collectionCrsObject.crs = collection.crs;
|
|
78
|
+
if (typeof collection.storageCrs !== "undefined")
|
|
79
|
+
collectionCrsObject.storageCrs = collection.storageCrs;
|
|
80
|
+
const layer = {
|
|
81
|
+
description: collection.description,
|
|
82
|
+
id: name,
|
|
83
|
+
name,
|
|
84
|
+
title: collection.title,
|
|
85
|
+
keywords: collection.keywords
|
|
86
|
+
? collection.keywords
|
|
87
|
+
: [],
|
|
88
|
+
defaultReference: 'CRS:84',
|
|
89
|
+
links: collection.links,
|
|
90
|
+
outputFormats: options.filterCollectionsByLinkType ?
|
|
91
|
+
this.filterCollectionLinks(collection.links, options.filterCollectionsByLinkType).map(link => this.detectTypeFormat(link))
|
|
92
|
+
:
|
|
93
|
+
collection.links.map(link => this.detectTypeFormat(link)),
|
|
94
|
+
extent: collection.extent,
|
|
95
|
+
...collectionCrsObject
|
|
96
|
+
};
|
|
97
|
+
return layer;
|
|
98
|
+
});
|
|
99
|
+
// console.log(featureTypes);
|
|
100
|
+
const o = {
|
|
101
|
+
name: '',
|
|
102
|
+
collections: foundCollections.map(col => ({ ...col, crs: col.crs ? col.crs : [], links: col.links.map(l => resolveLink(l, collectionsLink.href)) })),
|
|
103
|
+
version: responseOpenApi ? responseOpenApi.openapi : '',
|
|
104
|
+
service: '',
|
|
105
|
+
info: responseOpenApi ? responseOpenApi.info : {},
|
|
106
|
+
...crsArray,
|
|
107
|
+
serverOptions: serverOptions,
|
|
108
|
+
links: jsonObject.links.map(l => resolveLink(l, requestUrl)),
|
|
109
|
+
baseUrl,
|
|
110
|
+
tileMatrixSetsUrl: linkToTileMatrixSets ? resolveLink(linkToTileMatrixSets, requestUrl).href : undefined
|
|
111
|
+
};
|
|
112
|
+
resolve(o);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
reject("Invalid format: (property 'links' contains no links with rel=data");
|
|
117
|
+
}
|
|
118
|
+
}, () => {
|
|
119
|
+
reject("Not JSON");
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
reject(response.status);
|
|
124
|
+
}
|
|
125
|
+
}, (err) => {
|
|
126
|
+
reject(err);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
static fetchLinkContentAsJSON(link, options, serverOptions) {
|
|
131
|
+
return new Promise((resolve) => {
|
|
132
|
+
OgcOpenApiFetchTools.fetch(link.href, { method: "GET", credentials: options.credentials ? "same-origin" : "omit", headers: options.requestHeaders }, serverOptions).then((result) => {
|
|
133
|
+
if (result.status === 200) {
|
|
134
|
+
result.json().then((json) => resolve(json));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
resolve(undefined);
|
|
138
|
+
}
|
|
139
|
+
}, () => {
|
|
140
|
+
resolve(undefined);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
static filterCollectionLinks(links, linkType) {
|
|
145
|
+
switch (linkType) {
|
|
146
|
+
case CollectionLinkType.Items:
|
|
147
|
+
case CollectionLinkType.Map:
|
|
148
|
+
case CollectionLinkType.Styles:
|
|
149
|
+
case CollectionLinkType.Tiles:
|
|
150
|
+
case CollectionLinkType.VectorTiles:
|
|
151
|
+
return links.filter((link) => CollectionLinkTypeAlternatives[linkType].some(e => e === link.rel));
|
|
152
|
+
default:
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
static getDataLink(currentLayer, preferedFormat) {
|
|
157
|
+
const dataLink = OgcOpenApiGetCapabilities.filterCollectionLinks(currentLayer.links, CollectionLinkType.Items).find((link) => link.type === preferedFormat);
|
|
158
|
+
return dataLink ? dataLink.href : '';
|
|
159
|
+
}
|
|
160
|
+
static detectTypeFormat(link) {
|
|
161
|
+
if (link.type)
|
|
162
|
+
return link.type;
|
|
163
|
+
for (const key in CollectionLinkTypeAlternatives) {
|
|
164
|
+
if (CollectionLinkTypeAlternatives.hasOwnProperty(key) && CollectionLinkTypeAlternatives[key].some(e => e === link.rel)) {
|
|
165
|
+
if (CollectionLinkTypeDefaultFormat[key])
|
|
166
|
+
return CollectionLinkTypeDefaultFormat[key];
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return "application/json";
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The tile matrix sets of the server, with their definitions. A definition that cannot be read is left out, so one
|
|
174
|
+
* broken definition does not hide the others. Rejects only when none can be read.
|
|
175
|
+
*/
|
|
176
|
+
static async fetchTileSetsInFull(capabilities, options) {
|
|
177
|
+
const tileSetMetaArray = await this.fetchTileSets(capabilities, options);
|
|
178
|
+
const settled = await Promise.all(tileSetMetaArray.map(tml => this.fetchTileset(capabilities, tml, options).then(tileSet => ({ tileSet, error: undefined }), error => ({ tileSet: undefined, error }))));
|
|
179
|
+
const tileSets = settled.filter(s => s.tileSet).map(s => s.tileSet);
|
|
180
|
+
const failed = settled.find(s => !s.tileSet);
|
|
181
|
+
if (tileSets.length === 0 && failed)
|
|
182
|
+
throw failed.error;
|
|
183
|
+
return tileSets;
|
|
184
|
+
}
|
|
185
|
+
static getQuadTreeCompatibleLevelOffset(tileMatrixSet) {
|
|
186
|
+
const levels = tileMatrixSet.tileMatrices;
|
|
187
|
+
const reference = levels[levels.length - 1];
|
|
188
|
+
for (let level = levels.length - 2; level >= 0; level--) {
|
|
189
|
+
const current = levels[level];
|
|
190
|
+
// tslint:disable-next-line:no-bitwise
|
|
191
|
+
const multiplier = 1 << (levels.length - level - 1);
|
|
192
|
+
const errorMargin = current.scaleDenominator * SCALE_DENOMINATOR_TOLERANCE;
|
|
193
|
+
if (Math.abs(current.scaleDenominator - reference.scaleDenominator * multiplier) > errorMargin) {
|
|
194
|
+
return level + 1;
|
|
195
|
+
}
|
|
196
|
+
if (current.pointOfOrigin[0] !== reference.pointOfOrigin[0]) {
|
|
197
|
+
return level + 1;
|
|
198
|
+
}
|
|
199
|
+
if (current.tileWidth !== reference.tileWidth || current.tileHeight !== reference.tileHeight) {
|
|
200
|
+
return level + 1;
|
|
201
|
+
}
|
|
202
|
+
if (typeof current.variableMatrixWidths !== "undefined") {
|
|
203
|
+
return level + 1;
|
|
204
|
+
}
|
|
205
|
+
if (current.matrixWidth !== (reference.matrixWidth / multiplier) || current.matrixHeight !== (reference.matrixHeight / multiplier)) {
|
|
206
|
+
return level + 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
static async fetchTileSets(capabilities, options) {
|
|
212
|
+
if (capabilities === null)
|
|
213
|
+
throw { error: true, message: "No capabilities" };
|
|
214
|
+
const url = capabilities.tileMatrixSetsUrl ? capabilities.tileMatrixSetsUrl : capabilities.baseUrl + "tileMatrixSets";
|
|
215
|
+
const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, url, options);
|
|
216
|
+
if (!data.tileMatrixSets)
|
|
217
|
+
throw { error: true, message: "tileMatrixSets not defined" };
|
|
218
|
+
const resolve = (href) => OgcOpenApiFetchTools.resolveUrl(href, url, capabilities.serverOptions);
|
|
219
|
+
return data.tileMatrixSets.map(tml => ({
|
|
220
|
+
...tml,
|
|
221
|
+
href: resolve(tml.href),
|
|
222
|
+
links: (tml.links ? tml.links : []).map(l => ({ ...l, href: resolve(l.href) }))
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
// GETs a JSON document. Servers answer JSON for the Accept header, or for the f parameter that their links carry.
|
|
226
|
+
static async fetchJson(capabilities, href, options) {
|
|
227
|
+
let result;
|
|
228
|
+
try {
|
|
229
|
+
result = await OgcOpenApiFetchTools.fetch(href, {
|
|
230
|
+
method: "GET",
|
|
231
|
+
credentials: options?.credentials ? "same-origin" : "omit",
|
|
232
|
+
headers: { Accept: "application/json", ...(options?.requestHeaders ? options.requestHeaders : {}) }
|
|
233
|
+
}, capabilities.serverOptions);
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
throw { error: true, message: err.message };
|
|
237
|
+
}
|
|
238
|
+
if (result.status !== 200)
|
|
239
|
+
throw { error: true, message: "Invalid response: " + result.status };
|
|
240
|
+
try {
|
|
241
|
+
return await result.json();
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
throw { error: true, message: "Not JSON data" };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// The link that identifies the tile matrix set of a tileset, relative to the document that has it
|
|
248
|
+
static getTilingSchemeHref(capabilities, links, documentUrl) {
|
|
249
|
+
const tilingScheme = links.find(l => isRel(l, "tiling-scheme"));
|
|
250
|
+
return tilingScheme ? OgcOpenApiFetchTools.resolveUrl(tilingScheme.href, documentUrl, capabilities.serverOptions) : undefined;
|
|
251
|
+
}
|
|
252
|
+
static getTilesLink(capabilities, currentCollection, tileMatrixId, options, linkType = CollectionLinkType.Tiles) {
|
|
253
|
+
return this.fetchCollectionTileSet(capabilities, currentCollection, tileMatrixId, options, linkType).then(tileSet => tileSet.links);
|
|
254
|
+
}
|
|
255
|
+
// The tilesets link of a collection, the JSON one when the server types its links
|
|
256
|
+
static getTileSetsHref(collection, linkType) {
|
|
257
|
+
const dataLinks = OgcOpenApiGetCapabilities.filterCollectionLinks(collection.links, linkType);
|
|
258
|
+
const link = dataLinks.find((link) => link.type === "application/json");
|
|
259
|
+
return link ? link.href : dataLinks.length > 0 ? dataLinks[0].href : '';
|
|
260
|
+
}
|
|
261
|
+
// The tilesets link of the landing page: the tilesets of the dataset, with all its collections in each tile
|
|
262
|
+
static getDatasetTileSetsHref(capabilities, linkType) {
|
|
263
|
+
const dataLinks = OgcOpenApiGetCapabilities.filterCollectionLinks(capabilities.links ? capabilities.links : [], linkType);
|
|
264
|
+
const link = dataLinks.find((link) => link.type === "application/json") || dataLinks.find((link) => !link.type) || dataLinks[0];
|
|
265
|
+
return link ? link.href : '';
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Whether the server tiles the dataset as a whole, all its collections in each tile, for linkType Tiles or VectorTiles
|
|
269
|
+
*/
|
|
270
|
+
static hasDatasetTileSets(capabilities, linkType) {
|
|
271
|
+
return capabilities !== null && OgcOpenApiGetCapabilities.getDatasetTileSetsHref(capabilities, linkType) !== '';
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Lists the tilesets of a collection: the tile matrix sets the collection is tiled in, which can be fewer than the
|
|
275
|
+
* tile matrix sets of the server.
|
|
276
|
+
*/
|
|
277
|
+
static async fetchCollectionTileSets(capabilities, collection, linkType = CollectionLinkType.Tiles, options) {
|
|
278
|
+
if (capabilities === null)
|
|
279
|
+
throw { error: true, message: "No capabilities" };
|
|
280
|
+
const href = OgcOpenApiGetCapabilities.getTileSetsHref(collection, linkType);
|
|
281
|
+
if (href === '')
|
|
282
|
+
throw { error: true, message: "Collection " + collection.id + " has no " + linkType + " link" };
|
|
283
|
+
return OgcOpenApiGetCapabilities.fetchTileSetList(capabilities, href, options);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Lists the tilesets of the dataset (/tiles of the landing page): each tile has the data of all its collections.
|
|
287
|
+
* Some servers tile only the dataset (PDOK).
|
|
288
|
+
*/
|
|
289
|
+
static async fetchDatasetTileSets(capabilities, linkType = CollectionLinkType.Tiles, options) {
|
|
290
|
+
if (capabilities === null)
|
|
291
|
+
throw { error: true, message: "No capabilities" };
|
|
292
|
+
const href = OgcOpenApiGetCapabilities.getDatasetTileSetsHref(capabilities, linkType);
|
|
293
|
+
if (href === '')
|
|
294
|
+
throw { error: true, message: "The dataset has no " + linkType + " link" };
|
|
295
|
+
return OgcOpenApiGetCapabilities.fetchTileSetList(capabilities, href, options);
|
|
296
|
+
}
|
|
297
|
+
static async fetchTileSetList(capabilities, href, options) {
|
|
298
|
+
const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, href, options);
|
|
299
|
+
if (!Array.isArray(data.tilesets))
|
|
300
|
+
throw { error: true, message: "Response has no tilesets" };
|
|
301
|
+
const tileSets = [];
|
|
302
|
+
for (const tileSet of data.tilesets) {
|
|
303
|
+
const links = tileSet.links ? tileSet.links : [];
|
|
304
|
+
const selfLinks = links.filter(l => l.rel === "self");
|
|
305
|
+
const self = selfLinks.find(l => l.type === "application/json") || selfLinks[0];
|
|
306
|
+
if (!self)
|
|
307
|
+
continue;
|
|
308
|
+
tileSets.push({
|
|
309
|
+
tileMatrixSetURI: tileSet.tileMatrixSetURI,
|
|
310
|
+
tileMatrixSetId: tileSet.tileMatrixSetId,
|
|
311
|
+
dataType: tileSet.dataType,
|
|
312
|
+
crs: typeof tileSet.crs === "string" ? tileSet.crs : undefined,
|
|
313
|
+
href: OgcOpenApiFetchTools.resolveUrl(self.href, href, capabilities.serverOptions),
|
|
314
|
+
tilingSchemeHref: OgcOpenApiGetCapabilities.getTilingSchemeHref(capabilities, links, href),
|
|
315
|
+
tileMatrixSet: OgcOpenApiGetCapabilities.getInlineTileMatrixSet(tileSet),
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return tileSets;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* The tile matrix set of a tileset among the tile matrix sets of the server (fetchTileSetsInFull): by URI, which
|
|
322
|
+
* servers give with their own ids (CubeWerx: WebMercatorQuad is smerc), then by id.
|
|
323
|
+
*/
|
|
324
|
+
static matchTileMatrixSet(tileSet, tileMatrixSets) {
|
|
325
|
+
const lastSegment = (url) => url.split("?")[0].replace(/\/$/, "").split("/").pop();
|
|
326
|
+
const byUri = tileSet.tileMatrixSetURI ? tileMatrixSets.find(t => OgcOpenApiGetCapabilities.sameUri(t.uri, tileSet.tileMatrixSetURI)) : undefined;
|
|
327
|
+
if (byUri)
|
|
328
|
+
return byUri;
|
|
329
|
+
const ids = [tileSet.tileMatrixSetId,
|
|
330
|
+
tileSet.tileMatrixSetURI ? lastSegment(tileSet.tileMatrixSetURI) : undefined,
|
|
331
|
+
tileSet.tilingSchemeHref ? lastSegment(tileSet.tilingSchemeHref) : undefined].filter(id => !!id);
|
|
332
|
+
return tileMatrixSets.find(t => ids.indexOf(t.id) > -1);
|
|
333
|
+
}
|
|
334
|
+
// Both forms name the same resource: http or https, the case of the scheme and host, a trailing slash
|
|
335
|
+
static sameUri(a, b) {
|
|
336
|
+
const normalize = (uri) => uri.trim().replace(/\/$/, "")
|
|
337
|
+
.replace(/^https?:\/\/[^/]*/i, prefix => prefix.toLowerCase().replace(/^https:/, "http:"));
|
|
338
|
+
return !!a && !!b && normalize(a) === normalize(b);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* The tile matrix set of a tileset: matched among the tile matrix sets of the server, or otherwise fetched from the
|
|
342
|
+
* tiling-scheme link of the tileset. A tileset in a list of tilesets is a summary that need not identify its tile
|
|
343
|
+
* matrix set, then the tileset itself is read (CubeWerx).
|
|
344
|
+
*/
|
|
345
|
+
static async fetchTileMatrixSetOfTileSet(capabilities, tileSet, tileMatrixSets, options) {
|
|
346
|
+
if (capabilities === null)
|
|
347
|
+
throw { error: true, message: "No capabilities" };
|
|
348
|
+
if (tileSet.tileMatrixSet)
|
|
349
|
+
return tileSet.tileMatrixSet;
|
|
350
|
+
let identified = tileSet;
|
|
351
|
+
if (!tileSet.tileMatrixSetURI && !tileSet.tileMatrixSetId && !tileSet.tilingSchemeHref) {
|
|
352
|
+
identified = { ...tileSet, ...await OgcOpenApiGetCapabilities.fetchTileSetIdentity(capabilities, tileSet.href, options) };
|
|
353
|
+
if (identified.tileMatrixSet)
|
|
354
|
+
return identified.tileMatrixSet;
|
|
355
|
+
}
|
|
356
|
+
const match = OgcOpenApiGetCapabilities.matchTileMatrixSet(identified, tileMatrixSets);
|
|
357
|
+
if (match)
|
|
358
|
+
return match;
|
|
359
|
+
if (!identified.tilingSchemeHref) {
|
|
360
|
+
throw { error: true, message: "No tile matrix set for " + (identified.tileMatrixSetURI || identified.href) };
|
|
361
|
+
}
|
|
362
|
+
return OgcOpenApiGetCapabilities.fetchTileset(capabilities, { id: identified.tileMatrixSetId, title: "", links: [{ rel: "self", type: "application/json", title: "", href: identified.tilingSchemeHref }] }, options);
|
|
363
|
+
}
|
|
364
|
+
// What identifies the tile matrix set in a tileset: its URI, its id or its tiling-scheme link
|
|
365
|
+
static async fetchTileSetIdentity(capabilities, href, options) {
|
|
366
|
+
const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, href, options);
|
|
367
|
+
return {
|
|
368
|
+
tileMatrixSetURI: data.tileMatrixSetURI,
|
|
369
|
+
tileMatrixSetId: data.tileMatrixSetId,
|
|
370
|
+
tilingSchemeHref: OgcOpenApiGetCapabilities.getTilingSchemeHref(capabilities, data.links ? data.links : [], href),
|
|
371
|
+
tileMatrixSet: OgcOpenApiGetCapabilities.getInlineTileMatrixSet(data),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
// A tileset can include the definition of its tile matrix set instead of linking it
|
|
375
|
+
static getInlineTileMatrixSet(tileSet) {
|
|
376
|
+
const tileMatrixSet = tileSet ? tileSet.tileMatrixSet : undefined;
|
|
377
|
+
return tileMatrixSet && typeof tileMatrixSet.id !== "undefined" && Array.isArray(tileMatrixSet.tileMatrices) && tileMatrixSet.crs ?
|
|
378
|
+
tileMatrixSet : undefined;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Fetches the tileset of a collection for one tile matrix set: the tile URL templates (rel item) and, for vector
|
|
382
|
+
* tiles, the layers contained in each tile.
|
|
383
|
+
*/
|
|
384
|
+
static async fetchCollectionTileSet(capabilities,
|
|
385
|
+
// null for a tileset of the dataset
|
|
386
|
+
currentCollection,
|
|
387
|
+
// The id of the tile matrix set, or a tileset from fetchCollectionTileSets or fetchDatasetTileSets
|
|
388
|
+
tileMatrix, options, linkType = CollectionLinkType.Tiles) {
|
|
389
|
+
if (capabilities === null)
|
|
390
|
+
throw { error: true, message: "No capabilities" };
|
|
391
|
+
const tileSetsHref = currentCollection ?
|
|
392
|
+
OgcOpenApiGetCapabilities.getTileSetsHref(currentCollection, linkType) :
|
|
393
|
+
OgcOpenApiGetCapabilities.getDatasetTileSetsHref(capabilities, linkType);
|
|
394
|
+
const tileInfoUrl = typeof tileMatrix === "string" ? OgcOpenApiFetchTools.cleanUrl(tileSetsHref) + tileMatrix : tileMatrix.href;
|
|
395
|
+
// pygeoapi answers 500 without f=json or an Accept header
|
|
396
|
+
const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, tileInfoUrl, options);
|
|
397
|
+
const links = data.links ? data.links.filter(l => l.rel === "item" || l.rel === "items").map(a => ({ ...a, href: OgcOpenApiFetchTools.resolveUrl(a.href, tileInfoUrl, capabilities.serverOptions) })) : [];
|
|
398
|
+
if (links.length === 0)
|
|
399
|
+
throw { error: true, message: "Invalid" };
|
|
400
|
+
return {
|
|
401
|
+
dataType: data.dataType,
|
|
402
|
+
links,
|
|
403
|
+
layers: data.layers ? data.layers : [],
|
|
404
|
+
tileMatrixSetLimits: data.tileMatrixSetLimits,
|
|
405
|
+
boundingBox: data.boundingBox && Array.isArray(data.boundingBox.lowerLeft) && Array.isArray(data.boundingBox.upperRight) ? data.boundingBox : undefined,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Fetches the definition of a tile matrix set, by its JSON link as the server gives it: with the query that tells
|
|
410
|
+
* the server to answer JSON (f=json), if it has one.
|
|
411
|
+
*/
|
|
412
|
+
static async fetchTileset(capabilities, tileset, options) {
|
|
413
|
+
if (capabilities === null)
|
|
414
|
+
throw { error: true, message: "No capabilities" };
|
|
415
|
+
const jsonLink = tileset.links.find(l => l.type === "application/json") || tileset.links.find(l => !l.type) || tileset.links[0];
|
|
416
|
+
if (!jsonLink)
|
|
417
|
+
throw { error: true, message: "Tile matrix set " + tileset.id + " has no link" };
|
|
418
|
+
const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, jsonLink.href, options);
|
|
419
|
+
if (typeof data.id === "undefined" || !data.tileMatrices || !data.crs)
|
|
420
|
+
throw { error: true, message: "TileSet has invalid data" };
|
|
421
|
+
return data;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=OgcOpenApiGetCapabilities.js.map
|