@open-pioneer/map 0.1.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/CHANGELOG.md +12 -0
- package/LICENSE +202 -0
- package/MapRegistryImpl.d.ts +15 -0
- package/MapRegistryImpl.js +89 -0
- package/MapRegistryImpl.js.map +1 -0
- package/README.md +653 -0
- package/_virtual/_virtual-pioneer-module_react-hooks.js +7 -0
- package/_virtual/_virtual-pioneer-module_react-hooks.js.map +1 -0
- package/api/MapConfig.d.ts +111 -0
- package/api/MapModel.d.ts +112 -0
- package/api/MapRegistry.d.ts +54 -0
- package/api/index.d.ts +12 -0
- package/api/layers/SimpleLayer.d.ts +24 -0
- package/api/layers/SimpleLayer.js +6 -0
- package/api/layers/SimpleLayer.js.map +1 -0
- package/api/layers/WMSLayer.d.ts +42 -0
- package/api/layers/WMSLayer.js +6 -0
- package/api/layers/WMSLayer.js.map +1 -0
- package/api/layers/base.d.ts +170 -0
- package/api/layers/index.d.ts +3 -0
- package/api/shared.d.ts +10 -0
- package/index.d.ts +1 -0
- package/index.js +11 -0
- package/index.js.map +1 -0
- package/layers/BkgTopPlusOpen.d.ts +21 -0
- package/layers/BkgTopPlusOpen.js +61 -0
- package/layers/BkgTopPlusOpen.js.map +1 -0
- package/model/AbstractLayer.d.ts +24 -0
- package/model/AbstractLayer.js +133 -0
- package/model/AbstractLayer.js.map +1 -0
- package/model/AbstractLayerBase.d.ts +37 -0
- package/model/AbstractLayerBase.js +106 -0
- package/model/AbstractLayerBase.js.map +1 -0
- package/model/LayerCollectionImpl.d.ts +27 -0
- package/model/LayerCollectionImpl.js +226 -0
- package/model/LayerCollectionImpl.js.map +1 -0
- package/model/MapModelImpl.d.ts +19 -0
- package/model/MapModelImpl.js +179 -0
- package/model/MapModelImpl.js.map +1 -0
- package/model/SublayersCollectionImpl.d.ts +15 -0
- package/model/SublayersCollectionImpl.js +29 -0
- package/model/SublayersCollectionImpl.js.map +1 -0
- package/model/createMapModel.d.ts +3 -0
- package/model/createMapModel.js +154 -0
- package/model/createMapModel.js.map +1 -0
- package/model/layers/SimpleLayerImpl.d.ts +9 -0
- package/model/layers/SimpleLayerImpl.js +10 -0
- package/model/layers/SimpleLayerImpl.js.map +1 -0
- package/model/layers/WMSLayerImpl.d.ts +29 -0
- package/model/layers/WMSLayerImpl.js +177 -0
- package/model/layers/WMSLayerImpl.js.map +1 -0
- package/package.json +67 -0
- package/projections.d.ts +27 -0
- package/projections.js +15 -0
- package/projections.js.map +1 -0
- package/services.d.ts +1 -0
- package/services.js +2 -0
- package/services.js.map +1 -0
- package/ui/MapAnchor.d.ts +49 -0
- package/ui/MapAnchor.js +91 -0
- package/ui/MapAnchor.js.map +1 -0
- package/ui/MapContainer.d.ts +60 -0
- package/ui/MapContainer.js +192 -0
- package/ui/MapContainer.js.map +1 -0
- package/ui/MapContext.d.ts +11 -0
- package/ui/MapContext.js +17 -0
- package/ui/MapContext.js.map +1 -0
- package/ui/hooks.d.ts +24 -0
- package/ui/hooks.js +73 -0
- package/ui/hooks.js.map +1 -0
- package/ui/styles.css +3 -0
- package/ui/styles.css.map +1 -0
- package/ui/useMapModel.d.ts +31 -0
- package/ui/useMapModel.js +21 -0
- package/ui/useMapModel.js.map +1 -0
- package/util/defer.d.ts +18 -0
- package/util/defer.js +21 -0
- package/util/defer.js.map +1 -0
- package/util/ol-test-support.d.ts +2 -0
- package/util/ol-test-support.js +24 -0
- package/util/ol-test-support.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
# @open-pioneer/map
|
|
2
|
+
|
|
3
|
+
This package integrates [OpenLayers](https://openlayers.org/) maps into a Trails application.
|
|
4
|
+
APIs provided by this package can be used to configure, embed and access the map and its contents.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
To use the map in your app, follow these two steps:
|
|
9
|
+
|
|
10
|
+
- Add a `MapContainer` component to your app (see [Map container component](#md:map-container-component)).
|
|
11
|
+
- Implement a `MapConfigProvider` (see [Map configuration](#md:map-configuration)).
|
|
12
|
+
|
|
13
|
+
To access or manipulate the content of the map programmatically, see [Using the map model](#using-the-map-model).
|
|
14
|
+
|
|
15
|
+
### Map container component
|
|
16
|
+
|
|
17
|
+
To integrate a `MapContainer` in an app, add the component to your React component, where you want the map to appear.
|
|
18
|
+
On the component specify the `mapId` of the map that you want to add.
|
|
19
|
+
|
|
20
|
+
Make sure that the parent component has an appropriate width and height (for example `100%`).
|
|
21
|
+
The `MapContainer` fills the entire available space.
|
|
22
|
+
|
|
23
|
+
Example: Integration of a map container with a given map ID:
|
|
24
|
+
|
|
25
|
+
```jsx
|
|
26
|
+
import { Box } from "@open-pioneer/chakra-integration";
|
|
27
|
+
import { MapContainer } from "@open-pioneer/map";
|
|
28
|
+
|
|
29
|
+
// ...
|
|
30
|
+
function AppUI() {
|
|
31
|
+
return (
|
|
32
|
+
<Box height="100%" overflow="hidden">
|
|
33
|
+
<MapContainer mapId="..." />
|
|
34
|
+
</Box>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> NOTE: There must be a `map.MapConfigProvider` that knows how to construct the map with the given ID (see [Map configuration](#md:map-configuration)).
|
|
40
|
+
|
|
41
|
+
The component itself uses the map registry service to create the map using the provided `mapId`.
|
|
42
|
+
|
|
43
|
+
### Map anchor component
|
|
44
|
+
|
|
45
|
+
To pass custom React components onto the map, the following anchor-points are provided:
|
|
46
|
+
|
|
47
|
+
- `top-left`
|
|
48
|
+
- `top-right`
|
|
49
|
+
- `bottom-left`
|
|
50
|
+
- `bottom-right`
|
|
51
|
+
|
|
52
|
+
Example: Integration of a map anchor component into the map container with position `bottom-right` and optional horizontal and vertical gap:
|
|
53
|
+
|
|
54
|
+
```jsx
|
|
55
|
+
<MapContainer mapId="...">
|
|
56
|
+
<MapAnchor position="bottom-right" horizontalGap={25} verticalGap={25}>
|
|
57
|
+
... {/** add map anchor content like other React components */}
|
|
58
|
+
</MapAnchor>
|
|
59
|
+
</MapContainer>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The component itself calculates the `maxHeight` and `maxWidth` according to the map view padding and optional `horizontalGap`and `verticalGap` to avoid content overflow.
|
|
63
|
+
In this case, the CSS property `overflow` is set to `hidden` to the map anchor component.
|
|
64
|
+
If no `verticalGap` is configured, a default vertical gap of `30px` is used.
|
|
65
|
+
|
|
66
|
+
> NOTE: To get the correct tab order, add the container anchor-points before other components.
|
|
67
|
+
|
|
68
|
+
By default, certain pointer events from map anchor children (such as `pointer-down`) are stopped from bubbling up towards the map.
|
|
69
|
+
This is done to "hide" those events from map interactions (such as drawing): this makes it possible to click into text or controls within a map anchor without interacting with the map.
|
|
70
|
+
This behavior can be disabled by setting the `stopEvents` property to `false`:
|
|
71
|
+
|
|
72
|
+
```jsx
|
|
73
|
+
<MapAnchor position="top-right" stopEvents={false}>
|
|
74
|
+
{/* Click events etc. will be seen by the map. This could be appropriate for non-interactive text-only overlays, for example. */}
|
|
75
|
+
</MapAnchor>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Map configuration
|
|
79
|
+
|
|
80
|
+
Register a service providing `map.MapConfigProvider` to configure the contents of a map.
|
|
81
|
+
Such a provider is typically located in an app.
|
|
82
|
+
|
|
83
|
+
Example: Configuration to register a service providing `map.MapConfigProvider`.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
// YOUR-APP/build.config.mjs
|
|
87
|
+
import { defineBuildConfig } from "@open-pioneer/build-support";
|
|
88
|
+
|
|
89
|
+
export default defineBuildConfig({
|
|
90
|
+
services: {
|
|
91
|
+
MapConfigProviderImpl: {
|
|
92
|
+
// Registers the service as a config provider
|
|
93
|
+
provides: ["map.MapConfigProvider"]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
ui: {
|
|
97
|
+
references: ["map.MapRegistry"]
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The service itself needs to implement the `MapConfigProvider` interface.
|
|
103
|
+
The following map options are supported:
|
|
104
|
+
|
|
105
|
+
- `initialView`,
|
|
106
|
+
- `projection`,
|
|
107
|
+
- `layers` (see [Layer configuration](#layer-configuration)),
|
|
108
|
+
- `advanced`
|
|
109
|
+
|
|
110
|
+
Always use the provided map model to access the map initially.
|
|
111
|
+
Use `.olMap` only, when the raw instance is required.
|
|
112
|
+
|
|
113
|
+
If an advanced configuration (fully constructed `OlView` instance) is used, some options (such as `initialView` or `projection`) cannot be applied anymore.
|
|
114
|
+
|
|
115
|
+
Example: Implementation of the service with `initialView.kind = position`.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// YOUR-APP/MapConfigProviderImpl.ts
|
|
119
|
+
import { MapConfig, MapConfigProvider } from "@open-pioneer/map";
|
|
120
|
+
|
|
121
|
+
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
122
|
+
async getMapConfig(): Promise<MapConfig> {
|
|
123
|
+
return {
|
|
124
|
+
initialView: {
|
|
125
|
+
kind: "position",
|
|
126
|
+
center: { x: 847541, y: 6793584 },
|
|
127
|
+
zoom: 14
|
|
128
|
+
},
|
|
129
|
+
projection: "EPSG:3857",
|
|
130
|
+
layers: [
|
|
131
|
+
// ...
|
|
132
|
+
]
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Example: Implementation of the service with `initialView.kind = extent`.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// YOUR-APP/MapConfigProviderImpl.ts
|
|
142
|
+
import { MapConfig, MapConfigProvider } from "@open-pioneer/map";
|
|
143
|
+
|
|
144
|
+
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
145
|
+
async getMapConfig(): Promise<MapConfig> {
|
|
146
|
+
return {
|
|
147
|
+
initialView: {
|
|
148
|
+
kind: "extent",
|
|
149
|
+
extent: {
|
|
150
|
+
xMin: 577252,
|
|
151
|
+
yMin: 6026906,
|
|
152
|
+
xMax: 1790460,
|
|
153
|
+
yMax: 7318386
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
projection: "EPSG:3857",
|
|
157
|
+
layers: [
|
|
158
|
+
// ...
|
|
159
|
+
]
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Example: Implementation of the service with an advanced configuration.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
// YOUR-APP/MapConfigProviderImpl.ts
|
|
169
|
+
import { MapConfig, MapConfigProvider } from "@open-pioneer/map";
|
|
170
|
+
|
|
171
|
+
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
172
|
+
async getMapConfig(): Promise<MapConfig> {
|
|
173
|
+
return {
|
|
174
|
+
advanced: {
|
|
175
|
+
view: new View({
|
|
176
|
+
center: [405948.17, 5757572.85],
|
|
177
|
+
zoom: 5
|
|
178
|
+
})
|
|
179
|
+
},
|
|
180
|
+
layers: [
|
|
181
|
+
// ...
|
|
182
|
+
]
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
> IMPORTANT: Not all OpenLayers [View](https://openlayers.org/en/latest/apidoc/module-ol_View-View.html) properties are supported.
|
|
189
|
+
> For example, you cannot set the target because the target is controlled by the `<MapContainer />`.
|
|
190
|
+
|
|
191
|
+
#### Layer configuration
|
|
192
|
+
|
|
193
|
+
Configure your custom layer inside the [Map configuration](#md:map-configuration) by using one of the layer classes provided by this package.
|
|
194
|
+
For example, `SimpleLayer` can be used to configure an arbitrary [`OpenLayers Layer`](https://openlayers.org/en/latest/apidoc/module-ol_layer_Layer-Layer.html) as `olLayer` property.
|
|
195
|
+
|
|
196
|
+
> **Layer Order**
|
|
197
|
+
>
|
|
198
|
+
> By default, layers are displayed in the order in which they are defined in the `layers` array.
|
|
199
|
+
> The later a layer is listed in the array, the higher up it is displayed in the map.
|
|
200
|
+
>
|
|
201
|
+
> Base layers are excluded from this rule: they are always displayed below all operational layers.
|
|
202
|
+
|
|
203
|
+
Example: Implementation of a layer configuration.
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
// YOUR-APP/MapConfigProviderImpl.ts
|
|
207
|
+
import { MapConfig, MapConfigProvider, SimpleLayer } from "@open-pioneer/map";
|
|
208
|
+
import TileLayer from "ol/layer/Tile";
|
|
209
|
+
import OSM from "ol/source/OSM";
|
|
210
|
+
|
|
211
|
+
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
212
|
+
async getMapConfig(): Promise<MapConfig> {
|
|
213
|
+
return {
|
|
214
|
+
layers: [
|
|
215
|
+
new SimpleLayer({
|
|
216
|
+
// minimal layer configuration
|
|
217
|
+
title: "OSM",
|
|
218
|
+
olLayer: new TileLayer({
|
|
219
|
+
source: new OSM()
|
|
220
|
+
})
|
|
221
|
+
}),
|
|
222
|
+
new SimpleLayer({
|
|
223
|
+
// layer configuration with optional properties
|
|
224
|
+
id: "abe0e3f8-0ba2-409c-b6b4-9d8429c732e3",
|
|
225
|
+
title: "OSM with UUID",
|
|
226
|
+
olLayer: new TileLayer({
|
|
227
|
+
source: new OSM()
|
|
228
|
+
}),
|
|
229
|
+
attributes: {
|
|
230
|
+
foo: "bar"
|
|
231
|
+
},
|
|
232
|
+
description: "additional description",
|
|
233
|
+
isBaseLayer: false,
|
|
234
|
+
visible: false
|
|
235
|
+
})
|
|
236
|
+
]
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Based on the example above, you can set different properties using the layer API (such as setting visibility, update custom metadata (`attributes`)).
|
|
243
|
+
|
|
244
|
+
Example: How to set different properties.
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
import { useMapModel } from "@open-pioneer/map";
|
|
248
|
+
|
|
249
|
+
const { map } = useMapModel(mapId);
|
|
250
|
+
const layer = map.layers.getLayerById("abe0e3f8-0ba2-409c-b6b4-9d8429c732e3");
|
|
251
|
+
|
|
252
|
+
layer.setDescription("new description");
|
|
253
|
+
layer.setTitle("new title");
|
|
254
|
+
layer.setVisible(true);
|
|
255
|
+
layer.updateAttributes({
|
|
256
|
+
foo: "bar"
|
|
257
|
+
});
|
|
258
|
+
layer.deleteAttribute("foo");
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
> NOTE: The visibility of base layers cannot be changed through the method `setVisible`.
|
|
262
|
+
> Call `activateBaseLayer` instead.
|
|
263
|
+
|
|
264
|
+
##### OGC API Features
|
|
265
|
+
|
|
266
|
+
To create an OGC API Features layer, use the `ogc-features` package.
|
|
267
|
+
Details about the necessary steps are described in the package's [README](../ogc-features/README.md) file.
|
|
268
|
+
|
|
269
|
+
##### Mapbox / MapLibre styles
|
|
270
|
+
|
|
271
|
+
To use layers of a Mapbox / MapLibre style document, use the class `MapboxVectorLayer` from the package `ol-mapbox-style` as in the following sample:
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
// YOUR-APP/MapConfigProviderImpl.ts
|
|
275
|
+
import { MapboxVectorLayer } from "ol-mapbox-style";
|
|
276
|
+
|
|
277
|
+
export const MAP_ID = "main";
|
|
278
|
+
|
|
279
|
+
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
280
|
+
mapId = MAP_ID;
|
|
281
|
+
|
|
282
|
+
async getMapConfig(): Promise<MapConfig> {
|
|
283
|
+
return {
|
|
284
|
+
projection: "EPSG:3857",
|
|
285
|
+
initialView: {
|
|
286
|
+
kind: "position",
|
|
287
|
+
center: {
|
|
288
|
+
x: 848890,
|
|
289
|
+
y: 6793350
|
|
290
|
+
},
|
|
291
|
+
zoom: 13
|
|
292
|
+
},
|
|
293
|
+
layers: [
|
|
294
|
+
{
|
|
295
|
+
title: "Abschnitte/Äste mit Unfällen (Mapbox Style)",
|
|
296
|
+
layer: new MapboxVectorLayer({
|
|
297
|
+
styleUrl: "https://demo.ldproxy.net/strassen/styles/default?f=mbs",
|
|
298
|
+
accessToken: null
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
As with the current version 12.0.0 of `ol-mapbox-style`, it is not possible to use the MapboxVectorLayer
|
|
308
|
+
with styleUrls in format `mbs` (parameter `f=mbs`) due to a bug. A patch has been provided for this and is active
|
|
309
|
+
with the current version of the trails base package.
|
|
310
|
+
The patch enables the user to explicitly set the `accessToken` to `null`, if it is not needed/supported.
|
|
311
|
+
|
|
312
|
+
Because of the changed licence of Mapbox as of version 2.0, we recommend to override the implementation with the code of MapLibre (see the main package.json of this repository for a sample).
|
|
313
|
+
|
|
314
|
+
##### OGC Web Map Tile Service (WMTS)
|
|
315
|
+
|
|
316
|
+
To create a layer configuration for a WMTS, use one of the following configuration approaches:
|
|
317
|
+
|
|
318
|
+
1. Predefine options
|
|
319
|
+
2. Request options from the services capabilities (see [OpenLayers API](https://openlayers.org/en/latest/apidoc/module-ol_source_WMTS.html#.optionsFromCapabilities))
|
|
320
|
+
|
|
321
|
+
Predefining the options results in faster startup of your application and prevents the startup process from being interrupted when a service is temporarily unavailable.
|
|
322
|
+
Requesting the options from the capabilities has the advantage that you do not have to track and adjust changes in the services' metadata and can integrate a service with less code.
|
|
323
|
+
|
|
324
|
+
Example: How to predefine all necessary options for a WMTS layer:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
// YOUR-APP/MapConfigProviderImpl.ts
|
|
328
|
+
export const MAP_ID = "main";
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Register custom projection to the global proj4js definitions.
|
|
332
|
+
*/
|
|
333
|
+
registerProjections({
|
|
334
|
+
"EPSG:31466":
|
|
335
|
+
"+proj=tmerc +lat_0=0 +lon_0=6 +k=1 +x_0=2500000 +y_0=0 +ellps=bessel +nadgrids=BETA2007.gsb +units=m +no_defs +type=crs"
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
339
|
+
mapId = MAP_ID;
|
|
340
|
+
|
|
341
|
+
async getMapConfig(): Promise<MapConfig> {
|
|
342
|
+
return {
|
|
343
|
+
initialView: {
|
|
344
|
+
kind: "position",
|
|
345
|
+
center: { x: 404747, y: 5757920 },
|
|
346
|
+
zoom: 14
|
|
347
|
+
},
|
|
348
|
+
projection: "EPSG:31466",
|
|
349
|
+
layers: [
|
|
350
|
+
new SimpleLayer({
|
|
351
|
+
id: "topplus_open",
|
|
352
|
+
title: "TopPlus Open",
|
|
353
|
+
isBaseLayer: true,
|
|
354
|
+
visible: true,
|
|
355
|
+
layer: new TileLayer({
|
|
356
|
+
source: createWMTSSource("web")
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
]
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function createWMTSSource(layer: "web" | "web_grau" | "web_light") {
|
|
365
|
+
const topLeftCorner = [-3803165.98427299, 8805908.08284866];
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Resolutions taken from AdV WMTS-Profil
|
|
369
|
+
* @see https://www.adv-online.de/AdV-Produkte/Standards-und-Produktblaetter/AdV-Profile/
|
|
370
|
+
*/
|
|
371
|
+
const resolutions = [
|
|
372
|
+
4891.96981025128, // AdV-Level 0 (1:17471320.7508974)
|
|
373
|
+
2445.98490512564, // AdV-Level 1 (1:8735660.37544872)
|
|
374
|
+
1222.99245256282, // AdV-Level 2 (1:4367830.18772436)
|
|
375
|
+
611.49622628141, // AdV-Level 3 (1:2183915.09386218)
|
|
376
|
+
305.748113140705, // AdV-Level 4 (1:1091957.54693109)
|
|
377
|
+
152.874056570353, // AdV-Level 5 (1:545978.773465545)
|
|
378
|
+
76.4370282851763, // AdV-Level 6 (1:272989,386732772)
|
|
379
|
+
38.2185141425881, // AdV-Level 7 (1:136494,693366386)
|
|
380
|
+
19.1092570712941, // AdV-Level 8 (1:68247,3466831931)
|
|
381
|
+
9.55462853564703, // AdV-Level 9 (1:34123,6733415966)
|
|
382
|
+
4.77731426782352, // AdV-Level 10 (1:17061,8366707983)
|
|
383
|
+
2.38865713391176, // AdV-Level 11 (1:8530,91833539914)
|
|
384
|
+
1.19432856695588, // AdV-Level 12 (1:4265,45916769957)
|
|
385
|
+
0.59716428347794 // AdV-Level 13 (1:2132,72958384978)
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* The length of matrixIds needs to match the length of the resolutions array
|
|
390
|
+
* @see https://openlayers.org/en/latest/apidoc/module-ol_tilegrid_WMTS-WMTSTileGrid.html
|
|
391
|
+
*/
|
|
392
|
+
const matrixIds = new Array(resolutions.length);
|
|
393
|
+
for (let i = 0; i < resolutions.length; i++) {
|
|
394
|
+
matrixIds[i] = i;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return new WMTS({
|
|
398
|
+
url: `https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/${layer}/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png`,
|
|
399
|
+
layer: "web_grau",
|
|
400
|
+
matrixSet: "EU_EPSG_25832_TOPPLUS",
|
|
401
|
+
format: "image/png",
|
|
402
|
+
projection: "EPSG:25832",
|
|
403
|
+
requestEncoding: "REST",
|
|
404
|
+
tileGrid: new WMTSTileGrid({
|
|
405
|
+
origin: topLeftCorner,
|
|
406
|
+
resolutions: resolutions,
|
|
407
|
+
matrixIds: matrixIds
|
|
408
|
+
}),
|
|
409
|
+
style: "default",
|
|
410
|
+
attributions: `Kartendarstellung und Präsentationsgraphiken: © Bundesamt für Kartographie und Geodäsie ${new Date().getFullYear()}, <a href="https://sg.geodatenzentrum.de/web_public/gdz/datenquellen/Datenquellen_TopPlusOpen.html" target="_blank">Datenquellen</a>`
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
> Note: The WMTS configuration (for example `topLeftCorner` or `matrixSet`) can be different for each service.
|
|
416
|
+
> Please have a look into the WMTS capabilities.
|
|
417
|
+
|
|
418
|
+
Example: How to create the WMTS source from the services capabilities:
|
|
419
|
+
|
|
420
|
+
```js
|
|
421
|
+
// YOUR-APP/SomeFile.ts
|
|
422
|
+
|
|
423
|
+
// Imports:
|
|
424
|
+
import { MapModel, registerProjections } from "@open-pioneer/map";
|
|
425
|
+
import WMTSCapabilities from "ol/format/WMTSCapabilities";
|
|
426
|
+
import { optionsFromCapabilities } from "ol/source/WMTS";
|
|
427
|
+
|
|
428
|
+
// Global setup: register UTM32 (only needed for this specific layer)
|
|
429
|
+
registerProjections({
|
|
430
|
+
"EPSG:31466":
|
|
431
|
+
"+proj=tmerc +lat_0=0 +lon_0=6 +k=1 +x_0=2500000 +y_0=0 +ellps=bessel +nadgrids=BETA2007.gsb +units=m +no_defs +type=crs"
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Later, for example in a service
|
|
435
|
+
const mapModel: MapModel = ... // retrieved via MapRegistry service
|
|
436
|
+
await mapModel.whenDisplayed();
|
|
437
|
+
|
|
438
|
+
const response = await fetch("https://sgx.geodatenzentrum.de/wmts_topplus_open/1.0.0/WMTSCapabilities.xml");
|
|
439
|
+
const responseText = await response.text();
|
|
440
|
+
|
|
441
|
+
const wmtsParser = new WMTSCapabilities();
|
|
442
|
+
const wmtsResult = wmtsParser.read(responseText);
|
|
443
|
+
const wmtsOptions = optionsFromCapabilities(wmtsResult, {
|
|
444
|
+
layer: "web_light",
|
|
445
|
+
matrixSet: "EU_EPSG_25832_TOPPLUS"
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
if (wmtsOptions) {
|
|
449
|
+
mapModel.layers.addLayer(new SimpleLayer({
|
|
450
|
+
id: "topplus_open_optionsFromCapabilities",
|
|
451
|
+
title: "TopPlus Open - created with optionsFromCapabilities()",
|
|
452
|
+
visible: false,
|
|
453
|
+
layer: new TileLayer({
|
|
454
|
+
source: new WMTS(wmtsOptions)
|
|
455
|
+
})
|
|
456
|
+
}));
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
> Note: To avoid adding layers twice (or error messages), check against the layer id with `getLayerById()`.
|
|
461
|
+
|
|
462
|
+
##### OGC Web Map Service (WMS)
|
|
463
|
+
|
|
464
|
+
To create a layer configuration for a WMS, use the following configuration approach:
|
|
465
|
+
|
|
466
|
+
Example: Create WMS layer configuration
|
|
467
|
+
|
|
468
|
+
```ts
|
|
469
|
+
// YOUR-APP/MapConfigProviderImpl.ts
|
|
470
|
+
import { MapConfig, MapConfigProvider, WMSLayer } from "@open-pioneer/map";
|
|
471
|
+
|
|
472
|
+
export const MAP_ID = "main";
|
|
473
|
+
|
|
474
|
+
export class MapConfigProviderImpl implements MapConfigProvider {
|
|
475
|
+
mapId = MAP_ID;
|
|
476
|
+
|
|
477
|
+
async getMapConfig(): Promise<MapConfig> {
|
|
478
|
+
return {
|
|
479
|
+
initialView: {
|
|
480
|
+
kind: "position",
|
|
481
|
+
center: { x: 404747, y: 5757920 },
|
|
482
|
+
zoom: 14
|
|
483
|
+
},
|
|
484
|
+
projection: "EPSG:25832",
|
|
485
|
+
layers: [
|
|
486
|
+
new WMSLayer({
|
|
487
|
+
title: "Schulstandorte",
|
|
488
|
+
url: "https://www.wms.nrw.de/wms/wms_nw_inspire-schulen",
|
|
489
|
+
|
|
490
|
+
// Configure service (sub-) layers
|
|
491
|
+
sublayers: [
|
|
492
|
+
{
|
|
493
|
+
name: "US.education",
|
|
494
|
+
title: "Schulen"
|
|
495
|
+
}
|
|
496
|
+
],
|
|
497
|
+
|
|
498
|
+
// Optional, additional options for the underlying ImageWMS source
|
|
499
|
+
sourceOptions: {
|
|
500
|
+
// Ratio 1 means image requests are the size of the map viewport
|
|
501
|
+
ratio: 1
|
|
502
|
+
}
|
|
503
|
+
})
|
|
504
|
+
]
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
#### Register additional projections
|
|
511
|
+
|
|
512
|
+
The map supports only the following projections by default: `EPSG:4326`, `EPSG:3857`, `EPSG:25832` and `EPSG:25833`.
|
|
513
|
+
To register additional projections to use them for the map, use the `registerProjections` function.
|
|
514
|
+
|
|
515
|
+
Example: How to register an additional projection to the global [proj4js](https://github.com/proj4js/proj4js) definition set by name (such as `"EPSG:4326"`) and projection definition (string defining the projection or an existing proj4 definition object):
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
import { registerProjections } from "@open-pioneer/map";
|
|
519
|
+
|
|
520
|
+
registerProjections({
|
|
521
|
+
"EPSG:31466":
|
|
522
|
+
"+proj=tmerc +lat_0=0 +lon_0=6 +k=1 +x_0=2500000 +y_0=0 +ellps=bessel +nadgrids=BETA2007.gsb +units=m +no_defs +type=crs"
|
|
523
|
+
// ... more projections
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Projection definitions can be accessed by the [epsg.io](https://epsg.io/) website or by searching the global [proj4js](https://github.com/proj4js/proj4js) definition set with a valid name.
|
|
528
|
+
|
|
529
|
+
Example: How to use the registered projection:
|
|
530
|
+
|
|
531
|
+
```ts
|
|
532
|
+
import { getProjection } from "@open-pioneer/map";
|
|
533
|
+
|
|
534
|
+
// Returns a raw proj4 projection definition (or undefined)
|
|
535
|
+
const proj = getProjection("EPSG:3035");
|
|
536
|
+
|
|
537
|
+
// proj can be used as "projection" in "getMapConfig" of MapConfigProvider implementation
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Using the map model
|
|
541
|
+
|
|
542
|
+
This package allows interacting with maps and their layers through multiple interfaces and classes.
|
|
543
|
+
|
|
544
|
+
The most important API items are as follows:
|
|
545
|
+
|
|
546
|
+
- The `MapRegistry` service (inject via `"map.MapRegistry"`).
|
|
547
|
+
This service is used to obtain a reference to the `MapModel` via `registry.getMapModel(mapId)`.
|
|
548
|
+
|
|
549
|
+
> NOTE: From inside a React component you can also use the hook `useMapModel(mapId)`.
|
|
550
|
+
|
|
551
|
+
- The `MapModel` represents a map in an application.
|
|
552
|
+
Through the `MapModel` one can obtain the map's base layers, operational layers and so on.
|
|
553
|
+
The `MapModel` also provides access to the raw OpenLayers `olMap` for advanced use cases.
|
|
554
|
+
|
|
555
|
+
> NOTE: The `olMap` is manipulated by the `MapModel` to implement its functionality (for example, to add or remove layer instances). When using the `olMap` directly, treat it carefully and as a shared resource.
|
|
556
|
+
|
|
557
|
+
- The `Layer` interface and its various implementations.
|
|
558
|
+
This interface is used to make common properties and methods available (such as `.title`, or `.setVisible`).
|
|
559
|
+
Layers may also have `.sublayers`, which support the same basic properties as other layer types.
|
|
560
|
+
|
|
561
|
+
As is the case in `MapModel`, one can retrieve the raw OpenLayers `olLayer` from a layer instance (the same restrictions apply, see above).
|
|
562
|
+
|
|
563
|
+
As a general rule of thumb, one should always prefer to use properties or methods provided by this package (if available) instead of manipulating the raw OpenLayers instances.
|
|
564
|
+
Manipulating raw instances directly may lead to unexpected results.
|
|
565
|
+
For example, other application components may not react to raw property changes correctly because they expect an "official" property to be changed instead.
|
|
566
|
+
|
|
567
|
+
This point is especially important for the map model's central features:
|
|
568
|
+
|
|
569
|
+
- Map composition (access and configuration of layers, base layers, removing layers)
|
|
570
|
+
- Layer visibility
|
|
571
|
+
- Custom layer metadata (`attributes`)
|
|
572
|
+
|
|
573
|
+
In those cases, the properties or methods provided by this package should always be used:
|
|
574
|
+
|
|
575
|
+
- `map.layers.addLayer(layer)` and `map.layers.removeLayerById(layerId)` to add or remove layers
|
|
576
|
+
- `map.layers.getAllLayers()`, `map.layers.getBaseLayers()`, `map.layers.getOperationalLayers()` etc. to access (top-level) layers
|
|
577
|
+
- `layer.setVisible(visible)` and `map.layers.activateBaseLayer(layerId)` to control visibility
|
|
578
|
+
- `layer.updateAttributes()` and `layer.deleteAttributes()` to change a layer's custom attributes
|
|
579
|
+
|
|
580
|
+
#### Layer classes
|
|
581
|
+
|
|
582
|
+
This package currently only provides two layer implementations:
|
|
583
|
+
|
|
584
|
+
- `SimpleLayer`.
|
|
585
|
+
Instances of this class can be used to integrate arbitrary OpenLayers `Layer` instances into the map by configuring the `olLayer` constructor option.
|
|
586
|
+
Note that one can only achieve basic integration through this method: more advanced features such as automatic legends or sublayers will not be available.
|
|
587
|
+
|
|
588
|
+
- `WMSLayer`.
|
|
589
|
+
Represents a WMS service embedded into the map.
|
|
590
|
+
Must be configured with the service's `url` and a set of sublayers.
|
|
591
|
+
|
|
592
|
+
We expect to implement more classes in the future.
|
|
593
|
+
|
|
594
|
+
#### Using the map model and layers in services
|
|
595
|
+
|
|
596
|
+
Example: Center map to given coordinates using the map model and set layer visibility using the layer instance.
|
|
597
|
+
|
|
598
|
+
```ts
|
|
599
|
+
import { ServiceOptions, ServiceType } from "@open-pioneer/runtime";
|
|
600
|
+
import { MAP_ID } from "./MapConfigProviderImpl";
|
|
601
|
+
import type { MapRegistry } from "@open-pioneer/map";
|
|
602
|
+
|
|
603
|
+
interface References {
|
|
604
|
+
mapRegistry: ServiceType<"map.MapRegistry">;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export class TestService {
|
|
608
|
+
private registry: MapRegistry;
|
|
609
|
+
|
|
610
|
+
constructor(options: ServiceOptions<References>) {
|
|
611
|
+
this.registry = options.references.mapRegistry;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
async centerBerlin() {
|
|
615
|
+
const model = await this.registry.getMapModel(MAP_ID);
|
|
616
|
+
model?.olMap?.getView().fit([1489200, 6894026, 1489200, 6894026], { maxZoom: 13 });
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
async setLayerVisible() {
|
|
620
|
+
const model = await this.registry.getMapModel(MAP_ID);
|
|
621
|
+
const layer = model?.layers.getLayerById("abe0e3f8-0ba2-409c-b6b4-9d8429c732e3");
|
|
622
|
+
layer?.setVisible(true);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
#### Using the map model in React components
|
|
628
|
+
|
|
629
|
+
To access the map model instance, use the React hook `useMapModel`.
|
|
630
|
+
|
|
631
|
+
Example: Center map to given coordinates using the map model.
|
|
632
|
+
|
|
633
|
+
```js
|
|
634
|
+
import { useMapModel } from "@open-pioneer/map";
|
|
635
|
+
import { MAP_ID } from "./MapConfigProviderImpl";
|
|
636
|
+
|
|
637
|
+
export function AppUI() {
|
|
638
|
+
// mapState.map may be undefined initially, if the map is still configuring.
|
|
639
|
+
// the object may may also be in an "error" state.
|
|
640
|
+
const mapState = useMapModel(MAP_ID);
|
|
641
|
+
|
|
642
|
+
const centerBerlin = () => {
|
|
643
|
+
const olMap = mapState.map?.olMap;
|
|
644
|
+
if (olMap) {
|
|
645
|
+
olMap?.getView().fit([1489200, 6894026, 1489200, 6894026], { maxZoom: 13 });
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
## License
|
|
652
|
+
|
|
653
|
+
Apache-2.0 (see `LICENSE` file)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useServiceInternal } from '@open-pioneer/runtime/react-integration';
|
|
2
|
+
|
|
3
|
+
const PACKAGE_NAME = "@open-pioneer/map";
|
|
4
|
+
const useService = /*@__PURE__*/ useServiceInternal.bind(undefined, PACKAGE_NAME);
|
|
5
|
+
|
|
6
|
+
export { useService };
|
|
7
|
+
//# sourceMappingURL=_virtual-pioneer-module_react-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_virtual-pioneer-module_react-hooks.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
|