@open-pioneer/ogc-features 1.3.0-dev.20260303160408 → 1.3.0-dev.20260310142705
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @open-pioneer/ogc-features
|
|
2
2
|
|
|
3
|
-
## 1.3.0-dev.
|
|
3
|
+
## 1.3.0-dev.20260310142705
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
@@ -98,17 +98,12 @@
|
|
|
98
98
|
### Patch Changes
|
|
99
99
|
|
|
100
100
|
- b152428: Update trails dependencies
|
|
101
|
-
- Updated dependencies [b152428]
|
|
102
|
-
- @open-pioneer/search@0.4.4
|
|
103
101
|
|
|
104
102
|
## 0.4.3
|
|
105
103
|
|
|
106
104
|
### Patch Changes
|
|
107
105
|
|
|
108
106
|
- 28e092a: Update dependencies
|
|
109
|
-
- Updated dependencies [7f5e58a]
|
|
110
|
-
- Updated dependencies [28e092a]
|
|
111
|
-
- @open-pioneer/search@0.4.3
|
|
112
107
|
|
|
113
108
|
## 0.4.2
|
|
114
109
|
|
|
@@ -119,11 +114,6 @@
|
|
|
119
114
|
- 6977f0b: Added `strategy` and `rewriteUrl` options to the vector source factory.
|
|
120
115
|
- 81bc7da: Update trails dependencies
|
|
121
116
|
- 2c092dc: Update dependencies
|
|
122
|
-
- Updated dependencies [4140646]
|
|
123
|
-
- Updated dependencies [4140646]
|
|
124
|
-
- Updated dependencies [81bc7da]
|
|
125
|
-
- Updated dependencies [2c092dc]
|
|
126
|
-
- @open-pioneer/search@0.4.2
|
|
127
117
|
|
|
128
118
|
## 0.4.1
|
|
129
119
|
|
|
@@ -141,51 +131,26 @@
|
|
|
141
131
|
|
|
142
132
|
- 1a8ad89: Update package.json metadata
|
|
143
133
|
- 6162979: Update versions of core packages
|
|
144
|
-
- Updated dependencies [1a8ad89]
|
|
145
|
-
- Updated dependencies [a0d8882]
|
|
146
|
-
- Updated dependencies [6162979]
|
|
147
|
-
- Updated dependencies [9334e81]
|
|
148
|
-
- @open-pioneer/search@0.4.0
|
|
149
134
|
|
|
150
135
|
## 0.3.1
|
|
151
136
|
|
|
152
|
-
### Patch Changes
|
|
153
|
-
|
|
154
|
-
- Updated dependencies [611ddb9]
|
|
155
|
-
- @open-pioneer/search@0.3.1
|
|
156
|
-
|
|
157
137
|
## 0.3.0
|
|
158
138
|
|
|
159
139
|
### Minor Changes
|
|
160
140
|
|
|
161
141
|
- ee7c2d4: Update runtime version.
|
|
162
142
|
|
|
163
|
-
### Patch Changes
|
|
164
|
-
|
|
165
|
-
- Updated dependencies [0883bbd]
|
|
166
|
-
- Updated dependencies [ee7c2d4]
|
|
167
|
-
- Updated dependencies [0456500]
|
|
168
|
-
- @open-pioneer/search@0.3.0
|
|
169
|
-
|
|
170
143
|
## 0.2.0
|
|
171
144
|
|
|
172
145
|
### Minor Changes
|
|
173
146
|
|
|
174
147
|
- 70349a8: Update to new core packages major versions
|
|
175
148
|
|
|
176
|
-
### Patch Changes
|
|
177
|
-
|
|
178
|
-
- Updated dependencies [70349a8]
|
|
179
|
-
- @open-pioneer/search@0.2.0
|
|
180
|
-
|
|
181
149
|
## 0.1.1
|
|
182
150
|
|
|
183
151
|
### Patch Changes
|
|
184
152
|
|
|
185
153
|
- dfc0896: Add OGC API Features search source
|
|
186
|
-
- Updated dependencies [6209d6c]
|
|
187
|
-
- Updated dependencies [565bd8b]
|
|
188
|
-
- @open-pioneer/search@0.1.0
|
|
189
154
|
|
|
190
155
|
## 0.1.0
|
|
191
156
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@open-pioneer/ogc-features",
|
|
4
|
-
"version": "1.3.0-dev.
|
|
4
|
+
"version": "1.3.0-dev.20260310142705",
|
|
5
5
|
"description": "This package provides utilities to work with OGC API Features services.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"open-pioneer-trails"
|
|
@@ -36,8 +36,12 @@ class OgcFeaturesVectorSource extends VectorSource {
|
|
|
36
36
|
format,
|
|
37
37
|
strategy: bbox,
|
|
38
38
|
attributions: options.attributions,
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
// NOTE: it is IMPORTANT that every individual parameter is named here.
|
|
40
|
+
// OpenLayers tests the length of the signature, `...args` to forward these parameters
|
|
41
|
+
// will _not_ work!
|
|
42
|
+
// See also https://github.com/openlayers/openlayers/blob/da23cb2025bec601439fdc69076cf34af7582cb9/src/ol/source/Vector.js#L1041-L1042
|
|
43
|
+
loader: (e, r, p, s, f) => {
|
|
44
|
+
this.#load(e, r, p, s, f);
|
|
41
45
|
},
|
|
42
46
|
...options.additionalOptions
|
|
43
47
|
});
|
|
@@ -104,7 +108,10 @@ class OgcFeaturesVectorSource extends VectorSource {
|
|
|
104
108
|
try {
|
|
105
109
|
metadata = await getCollectionMetadata(this.#collectionUrl, this.#httpService);
|
|
106
110
|
} catch (e) {
|
|
107
|
-
LOG.error(
|
|
111
|
+
LOG.error(
|
|
112
|
+
`Failed to retrieve collection metadata for collection '${this.#collectionUrl}'`,
|
|
113
|
+
e
|
|
114
|
+
);
|
|
108
115
|
throwAbortError();
|
|
109
116
|
}
|
|
110
117
|
try {
|
|
@@ -127,7 +134,10 @@ class OgcFeaturesVectorSource extends VectorSource {
|
|
|
127
134
|
try {
|
|
128
135
|
supportsOffset = await supportsOffsetStrategy(this.#itemsUrl, this.#httpService);
|
|
129
136
|
} catch (e) {
|
|
130
|
-
LOG.error(
|
|
137
|
+
LOG.error(
|
|
138
|
+
`Failed to retrieve collection information for collection '${this.#collectionUrl}'`,
|
|
139
|
+
e
|
|
140
|
+
);
|
|
131
141
|
throwAbortError();
|
|
132
142
|
}
|
|
133
143
|
const options = this.#options;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OgcFeaturesVectorSource.js","sources":["OgcFeaturesVectorSource.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { createAbortError, createLogger, isAbortError, throwAbortError } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { Extent } from \"ol/extent\";\nimport Feature from \"ol/Feature\";\nimport GeoJSON from \"ol/format/GeoJSON\";\nimport { bbox } from \"ol/loadingstrategy\";\nimport { Projection } from \"ol/proj\";\nimport VectorSource from \"ol/source/Vector\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { OgcFeatureVectorSourceOptions } from \"../api\";\nimport { CollectionMetadata, findMatchingCrs, getCollectionMetadata } from \"./Metadata\";\nimport { NextStrategy } from \"./NextStrategy\";\nimport { OffsetStrategy, supportsOffsetStrategy } from \"./OffsetStrategy\";\nimport { createCollectionRequestUrl } from \"./requestUtils\";\n\nconst LOG = createLogger(sourceId);\n\nconst CRS_OGC_CRS84 = \"http://www.opengis.net/def/crs/OGC/1.3/CRS84\";\n\ntype SuccessCallback = (features: Feature[]) => void;\ntype FailureCallback = () => void;\n\nexport class OgcFeaturesVectorSource extends VectorSource {\n #featureFormat: GeoJSON;\n #httpService: HttpService;\n\n #options: OgcFeatureVectorSourceOptions;\n #itemsUrl: string;\n #collectionUrl: string;\n\n #metadataPromise: Promise<CollectionMetadata> | undefined;\n #loadingStrategyPromise: Promise<\"offset\" | \"next\"> | undefined;\n\n // Cancels pending feature load operations.\n #featuresAbortController: AbortController | undefined;\n\n // Maps a map CRS to the corresponding request CRS that should be used for requests to the OGC API Features service.\n #mapCrsToRequestCrs: Record<string, string> = {\n // Special case: When map is in EPSG:4326, which defines lat/long-order for coordinate values,\n // make sure features are requested in CRS84, which has long/lat-order.\n // Reason for this special case is that OpenLayers always expects coordinates to be in long/lat-order,\n // even when the CRS definition specifies lat/long-order (as is the case for EPSG:4326).\n // CRS84 is mandated to be supported by all OGC API Features services, so we can safely assume that the service will support it.\n [\"4326\"]: CRS_OGC_CRS84,\n [\"EPSG:4326\"]: CRS_OGC_CRS84\n };\n\n constructor(options: OgcFeatureVectorSourceOptions, httpService: HttpService) {\n const format = new GeoJSON();\n super({\n format,\n strategy: bbox,\n attributions: options.attributions,\n loader: (...args) => {\n this.#load(...args);\n },\n ...options.additionalOptions\n });\n this.#featureFormat = format;\n this.#httpService = httpService;\n this.#options = options;\n this.#collectionUrl = `${options.baseUrl.replace(/\\/+$/, \"\")}/collections/${options.collectionId}`;\n this.#itemsUrl = `${this.#collectionUrl}/items`;\n }\n\n async #load(\n extent: Extent,\n _resolution: number,\n projection: Projection,\n success: SuccessCallback | undefined,\n failure: FailureCallback | undefined\n ) {\n try {\n const features = await this.#loadImpl(extent, projection);\n success?.(features);\n this.changed(); // Always trigger changed event to unstuck loading state\n } catch (e) {\n if (!isAbortError(e)) {\n LOG.error(\"Failed to load features from ogc service\", e);\n }\n failure?.();\n\n // Always trigger changed event to unstuck loading state\n // See https://github.com/openlayers/openlayers/issues/17335\n this.changed();\n }\n }\n\n async #loadImpl(extent: Extent, projection: Projection): Promise<Feature[]> {\n const [collectionMetadata, strategy] = await Promise.all([\n this.#loadCollectionMetadata(),\n this.#getLoadingStrategy()\n ]);\n\n // An extent-change should cancel open requests for older extents, because otherwise,\n // old and expensive requests could block new requests for a new extent\n // => no features are drawn on the current map for a long time.\n //TODO: More context\n this.#featuresAbortController?.abort(createAbortError());\n const abortController = (this.#featuresAbortController = new AbortController());\n const requestCrs = this.#getRequestCrs(collectionMetadata, projection);\n const fullUrl = this.#getRequestUrl(extent, requestCrs);\n const sharedOptions = {\n fullUrl,\n featureFormat: this.#featureFormat,\n limit: this.#options.limit,\n httpService: this.#httpService,\n signal: abortController.signal,\n onFeaturesLoaded: (features: Feature[]) => {\n LOG.debug(`Adding ${features.length} features`);\n this.addFeatures(features);\n }\n };\n let strategyImpl;\n switch (strategy) {\n case \"next\": {\n strategyImpl = new NextStrategy(sharedOptions);\n break;\n }\n case \"offset\":\n strategyImpl = new OffsetStrategy({\n ...sharedOptions,\n concurrency: this.#options.maxConcurrentRequests\n });\n break;\n }\n\n const features = await strategyImpl.load();\n LOG.debug(\"Finished loading features for extent:\", extent);\n return features;\n }\n\n // Fetches collection metadata from the service (once).\n async #loadCollectionMetadata() {\n const run = async () => {\n let metadata;\n try {\n metadata = await getCollectionMetadata(this.#collectionUrl, this.#httpService);\n } catch (e) {\n LOG.error(`Failed to retrieve collection metadata for collection '${this.#collectionUrl}'`, e);\n throwAbortError(); // Report error up the stack but only log error once\n }\n\n try {\n if (this.getAttributions() == null && metadata.attribution) {\n this.setAttributions(metadata.attribution);\n }\n } catch (e) {\n LOG.error(\"Failed to apply attributions\", e);\n throwAbortError(); // Report error up the stack but only log error once\n }\n return metadata;\n };\n\n const promise = (this.#metadataPromise ??= run());\n return await promise;\n }\n\n // Runs feature detection on the service (once).\n async #getLoadingStrategy() {\n const run = async () => {\n let supportsOffset;\n try {\n supportsOffset = await supportsOffsetStrategy(this.#itemsUrl, this.#httpService);\n } catch (e) {\n LOG.error(`Failed to retrieve collection information for collection '${this.#collectionUrl}'`, e);\n throwAbortError(); // Report error up the stack but only log error once\n }\n\n const options = this.#options;\n let strategy = options?.strategy || (supportsOffset ? \"offset\" : \"next\");\n if (strategy === \"offset\" && !supportsOffset) {\n strategy = \"next\";\n }\n return strategy;\n };\n\n const promise = (this.#loadingStrategyPromise ??= run());\n return await promise;\n }\n\n // Computes the appropriate request crs for the current configuration.\n #getRequestCrs(collectionMetadata: CollectionMetadata | undefined, projection: Projection) {\n const mapCrs = projection.getCode();\n\n const requestCrs = this.#options.crs ?? this.#mapCrsToRequestCrs[mapCrs];\n if (requestCrs) {\n return requestCrs;\n }\n\n const matchingMapCrs = findMatchingCrs(mapCrs, collectionMetadata?.crs);\n if (matchingMapCrs) {\n this.#mapCrsToRequestCrs[mapCrs] = matchingMapCrs;\n return matchingMapCrs;\n } else {\n LOG.error(`Map CRS '${mapCrs}' not supported by collection '${this.#collectionUrl}'.`);\n throwAbortError();\n }\n }\n\n #getRequestUrl(extent: Extent, requestCrs: string) {\n let requestUrl = createCollectionRequestUrl(this.#itemsUrl, extent, requestCrs);\n const rewriteUrl = this.#options.rewriteUrl;\n if (rewriteUrl) {\n requestUrl = rewriteUrl(requestUrl) ?? requestUrl;\n }\n return requestUrl;\n }\n}\n"],"names":["features"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OgcFeaturesVectorSource.js","sources":["OgcFeaturesVectorSource.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { createAbortError, createLogger, isAbortError, throwAbortError } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { Extent } from \"ol/extent\";\nimport Feature from \"ol/Feature\";\nimport GeoJSON from \"ol/format/GeoJSON\";\nimport { bbox } from \"ol/loadingstrategy\";\nimport { Projection } from \"ol/proj\";\nimport VectorSource from \"ol/source/Vector\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { OgcFeatureVectorSourceOptions } from \"../api\";\nimport { CollectionMetadata, findMatchingCrs, getCollectionMetadata } from \"./Metadata\";\nimport { NextStrategy } from \"./NextStrategy\";\nimport { OffsetStrategy, supportsOffsetStrategy } from \"./OffsetStrategy\";\nimport { createCollectionRequestUrl } from \"./requestUtils\";\n\nconst LOG = createLogger(sourceId);\n\nconst CRS_OGC_CRS84 = \"http://www.opengis.net/def/crs/OGC/1.3/CRS84\";\n\ntype SuccessCallback = (features: Feature[]) => void;\ntype FailureCallback = () => void;\n\nexport class OgcFeaturesVectorSource extends VectorSource {\n #featureFormat: GeoJSON;\n #httpService: HttpService;\n\n #options: OgcFeatureVectorSourceOptions;\n #itemsUrl: string;\n #collectionUrl: string;\n\n #metadataPromise: Promise<CollectionMetadata> | undefined;\n #loadingStrategyPromise: Promise<\"offset\" | \"next\"> | undefined;\n\n // Cancels pending feature load operations.\n #featuresAbortController: AbortController | undefined;\n\n // Maps a map CRS to the corresponding request CRS that should be used for requests to the OGC API Features service.\n #mapCrsToRequestCrs: Record<string, string> = {\n // Special case: When map is in EPSG:4326, which defines lat/long-order for coordinate values,\n // make sure features are requested in CRS84, which has long/lat-order.\n // Reason for this special case is that OpenLayers always expects coordinates to be in long/lat-order,\n // even when the CRS definition specifies lat/long-order (as is the case for EPSG:4326).\n // CRS84 is mandated to be supported by all OGC API Features services, so we can safely assume that the service will support it.\n [\"4326\"]: CRS_OGC_CRS84,\n [\"EPSG:4326\"]: CRS_OGC_CRS84\n };\n\n constructor(options: OgcFeatureVectorSourceOptions, httpService: HttpService) {\n const format = new GeoJSON();\n super({\n format,\n strategy: bbox,\n attributions: options.attributions,\n\n // NOTE: it is IMPORTANT that every individual parameter is named here.\n // OpenLayers tests the length of the signature, `...args` to forward these parameters\n // will _not_ work!\n // See also https://github.com/openlayers/openlayers/blob/da23cb2025bec601439fdc69076cf34af7582cb9/src/ol/source/Vector.js#L1041-L1042\n loader: (e, r, p, s, f) => {\n this.#load(e, r, p, s, f);\n },\n ...options.additionalOptions\n });\n this.#featureFormat = format;\n this.#httpService = httpService;\n this.#options = options;\n this.#collectionUrl = `${options.baseUrl.replace(/\\/+$/, \"\")}/collections/${options.collectionId}`;\n this.#itemsUrl = `${this.#collectionUrl}/items`;\n }\n\n async #load(\n extent: Extent,\n _resolution: number,\n projection: Projection,\n success: SuccessCallback | undefined,\n failure: FailureCallback | undefined\n ) {\n try {\n const features = await this.#loadImpl(extent, projection);\n success?.(features);\n this.changed(); // Always trigger changed event to unstuck loading state\n } catch (e) {\n if (!isAbortError(e)) {\n LOG.error(\"Failed to load features from ogc service\", e);\n }\n failure?.();\n\n // Always trigger changed event to unstuck loading state\n // See https://github.com/openlayers/openlayers/issues/17335\n this.changed();\n }\n }\n\n async #loadImpl(extent: Extent, projection: Projection): Promise<Feature[]> {\n const [collectionMetadata, strategy] = await Promise.all([\n this.#loadCollectionMetadata(),\n this.#getLoadingStrategy()\n ]);\n\n // An extent-change should cancel open requests for older extents, because otherwise,\n // old and expensive requests could block new requests for a new extent\n // => no features are drawn on the current map for a long time.\n //TODO: More context\n this.#featuresAbortController?.abort(createAbortError());\n const abortController = (this.#featuresAbortController = new AbortController());\n const requestCrs = this.#getRequestCrs(collectionMetadata, projection);\n const fullUrl = this.#getRequestUrl(extent, requestCrs);\n const sharedOptions = {\n fullUrl,\n featureFormat: this.#featureFormat,\n limit: this.#options.limit,\n httpService: this.#httpService,\n signal: abortController.signal,\n onFeaturesLoaded: (features: Feature[]) => {\n LOG.debug(`Adding ${features.length} features`);\n this.addFeatures(features);\n }\n };\n let strategyImpl;\n switch (strategy) {\n case \"next\": {\n strategyImpl = new NextStrategy(sharedOptions);\n break;\n }\n case \"offset\":\n strategyImpl = new OffsetStrategy({\n ...sharedOptions,\n concurrency: this.#options.maxConcurrentRequests\n });\n break;\n }\n\n const features = await strategyImpl.load();\n LOG.debug(\"Finished loading features for extent:\", extent);\n return features;\n }\n\n // Fetches collection metadata from the service (once).\n async #loadCollectionMetadata() {\n const run = async () => {\n let metadata;\n try {\n metadata = await getCollectionMetadata(this.#collectionUrl, this.#httpService);\n } catch (e) {\n LOG.error(\n `Failed to retrieve collection metadata for collection '${this.#collectionUrl}'`,\n e\n );\n throwAbortError(); // Report error up the stack but only log error once\n }\n\n try {\n if (this.getAttributions() == null && metadata.attribution) {\n this.setAttributions(metadata.attribution);\n }\n } catch (e) {\n LOG.error(\"Failed to apply attributions\", e);\n throwAbortError(); // Report error up the stack but only log error once\n }\n return metadata;\n };\n\n const promise = (this.#metadataPromise ??= run());\n return await promise;\n }\n\n // Runs feature detection on the service (once).\n async #getLoadingStrategy() {\n const run = async () => {\n let supportsOffset;\n try {\n supportsOffset = await supportsOffsetStrategy(this.#itemsUrl, this.#httpService);\n } catch (e) {\n LOG.error(\n `Failed to retrieve collection information for collection '${this.#collectionUrl}'`,\n e\n );\n throwAbortError(); // Report error up the stack but only log error once\n }\n\n const options = this.#options;\n let strategy = options?.strategy || (supportsOffset ? \"offset\" : \"next\");\n if (strategy === \"offset\" && !supportsOffset) {\n strategy = \"next\";\n }\n return strategy;\n };\n\n const promise = (this.#loadingStrategyPromise ??= run());\n return await promise;\n }\n\n // Computes the appropriate request crs for the current configuration.\n #getRequestCrs(collectionMetadata: CollectionMetadata | undefined, projection: Projection) {\n const mapCrs = projection.getCode();\n\n const requestCrs = this.#options.crs ?? this.#mapCrsToRequestCrs[mapCrs];\n if (requestCrs) {\n return requestCrs;\n }\n\n const matchingMapCrs = findMatchingCrs(mapCrs, collectionMetadata?.crs);\n if (matchingMapCrs) {\n this.#mapCrsToRequestCrs[mapCrs] = matchingMapCrs;\n return matchingMapCrs;\n } else {\n LOG.error(`Map CRS '${mapCrs}' not supported by collection '${this.#collectionUrl}'.`);\n throwAbortError();\n }\n }\n\n #getRequestUrl(extent: Extent, requestCrs: string) {\n let requestUrl = createCollectionRequestUrl(this.#itemsUrl, extent, requestCrs);\n const rewriteUrl = this.#options.rewriteUrl;\n if (rewriteUrl) {\n requestUrl = rewriteUrl(requestUrl) ?? requestUrl;\n }\n return requestUrl;\n }\n}\n"],"names":["features"],"mappings":"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"}
|