@geospatial-sdk/openlayers 0.0.5-dev.13 → 0.0.5-dev.15
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/dist/map/apply-context-diff.d.ts.map +1 -1
- package/dist/map/apply-context-diff.js +40 -1
- package/dist/map/create-map.d.ts.map +1 -1
- package/dist/map/create-map.js +54 -26
- package/lib/map/apply-context-diff.test.ts +2 -2
- package/lib/map/apply-context-diff.ts +48 -7
- package/lib/map/create-map.test.ts +59 -29
- package/lib/map/create-map.ts +94 -45
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-context-diff.d.ts","sourceRoot":"","sources":["../../lib/map/apply-context-diff.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,QAAQ,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"apply-context-diff.d.ts","sourceRoot":"","sources":["../../lib/map/apply-context-diff.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,QAAQ,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQtD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,cAAc,GAC1B,OAAO,CAAC,GAAG,CAAC,CAuFd"}
|
|
@@ -8,6 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { createLayer } from "./create-map";
|
|
11
|
+
import { fromLonLat, transformExtent } from "ol/proj";
|
|
12
|
+
import GeoJSON from "ol/format/GeoJSON";
|
|
13
|
+
const GEOJSON = new GeoJSON();
|
|
11
14
|
/**
|
|
12
15
|
* Apply a context diff to an OpenLayers map
|
|
13
16
|
* @param map
|
|
@@ -48,10 +51,46 @@ export function applyContextDiffToMap(map, contextDiff) {
|
|
|
48
51
|
// recreate changed layers
|
|
49
52
|
for (const layerChanged of contextDiff.layersChanged) {
|
|
50
53
|
layers.item(layerChanged.position).dispose();
|
|
51
|
-
createLayer(layerChanged.layer).then(layer => {
|
|
54
|
+
createLayer(layerChanged.layer).then((layer) => {
|
|
52
55
|
layers.setAt(layerChanged.position, layer);
|
|
53
56
|
});
|
|
54
57
|
}
|
|
58
|
+
if ("viewChanges" in contextDiff) {
|
|
59
|
+
const { viewChanges } = contextDiff;
|
|
60
|
+
const view = map.getView();
|
|
61
|
+
const projection = view.getProjection();
|
|
62
|
+
if (!viewChanges) {
|
|
63
|
+
return map;
|
|
64
|
+
}
|
|
65
|
+
if ("geometry" in viewChanges) {
|
|
66
|
+
const geom = GEOJSON.readGeometry(viewChanges.geometry);
|
|
67
|
+
view.fit(geom, {
|
|
68
|
+
size: map.getSize(),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else if ("extent" in viewChanges) {
|
|
72
|
+
view.fit(transformExtent(viewChanges.extent, "EPSG:4326", projection), {
|
|
73
|
+
size: map.getSize(),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const { center: centerInViewProj, zoom } = viewChanges;
|
|
78
|
+
const center = centerInViewProj
|
|
79
|
+
? fromLonLat(centerInViewProj, projection)
|
|
80
|
+
: [0, 0];
|
|
81
|
+
view.setCenter(center);
|
|
82
|
+
view.setZoom(zoom);
|
|
83
|
+
if (viewChanges.maxZoom) {
|
|
84
|
+
view.setMaxZoom(viewChanges.maxZoom);
|
|
85
|
+
}
|
|
86
|
+
// TODO: factorize this better
|
|
87
|
+
// if (viewChanges.maxExtent) {
|
|
88
|
+
// map.setView(new View({
|
|
89
|
+
//
|
|
90
|
+
// }))
|
|
91
|
+
// }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
55
94
|
return map;
|
|
56
95
|
});
|
|
57
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-map.d.ts","sourceRoot":"","sources":["../../lib/map/create-map.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,eAAe,EACf,cAAc,
|
|
1
|
+
{"version":3,"file":"create-map.d.ts","sourceRoot":"","sources":["../../lib/map/create-map.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,eAAe,EACf,cAAc,EAEf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,GAAG,MAAM,QAAQ,CAAC;AACzB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,KAAK,MAAM,gBAAgB,CAAC;AAyBnC,wBAAsB,WAAW,CAAC,UAAU,EAAE,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,CA8K7E;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAyBpE;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,UAAU,EACnB,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,GAC5B,OAAO,CAAC,GAAG,CAAC,CAKd;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,GAAG,CAAC,CAQd"}
|
package/dist/map/create-map.js
CHANGED
|
@@ -7,6 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
import { removeSearchParams, } from "@geospatial-sdk/core";
|
|
10
11
|
import Map from "ol/Map";
|
|
11
12
|
import View from "ol/View";
|
|
12
13
|
import TileLayer from "ol/layer/Tile";
|
|
@@ -17,13 +18,12 @@ import VectorSource from "ol/source/Vector";
|
|
|
17
18
|
import GeoJSON from "ol/format/GeoJSON";
|
|
18
19
|
import { fromLonLat } from "ol/proj";
|
|
19
20
|
import { bbox as bboxStrategy } from "ol/loadingstrategy";
|
|
20
|
-
import { removeSearchParams } from "@geospatial-sdk/core";
|
|
21
21
|
import { defaultStyle } from "./styles";
|
|
22
22
|
import VectorTileLayer from "ol/layer/VectorTile";
|
|
23
|
-
import { OGCMapTile, OGCVectorTile } from "ol/source";
|
|
23
|
+
import { OGCMapTile, OGCVectorTile, WMTS } from "ol/source";
|
|
24
24
|
import { MVT } from "ol/format";
|
|
25
|
-
import { OgcApiEndpoint, WfsEndpoint } from "@camptocamp/ogc-client";
|
|
26
|
-
const
|
|
25
|
+
import { OgcApiEndpoint, WfsEndpoint, WmtsEndpoint, } from "@camptocamp/ogc-client";
|
|
26
|
+
const GEOJSON = new GeoJSON();
|
|
27
27
|
const WFS_MAX_FEATURES = 10000;
|
|
28
28
|
export function createLayer(layerModel) {
|
|
29
29
|
var _a;
|
|
@@ -50,11 +50,36 @@ export function createLayer(layerModel) {
|
|
|
50
50
|
}),
|
|
51
51
|
});
|
|
52
52
|
break;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
case "wmts": {
|
|
54
|
+
const olLayer = new TileLayer({});
|
|
55
|
+
const endpoint = new WmtsEndpoint(layerModel.url);
|
|
56
|
+
endpoint.isReady().then((endpoint) => __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
var _b;
|
|
58
|
+
const layerName = (_b = endpoint.getSingleLayerName()) !== null && _b !== void 0 ? _b : layerModel.name;
|
|
59
|
+
const layer = endpoint.getLayerByName(layerName);
|
|
60
|
+
const matrixSet = layer.matrixSets[0];
|
|
61
|
+
const tileGrid = yield endpoint.getOpenLayersTileGrid(layer.name);
|
|
62
|
+
if (tileGrid === null) {
|
|
63
|
+
console.warn("A WMTS tile grid could not be created", layerModel);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const resourceUrl = layer.resourceLinks[0];
|
|
67
|
+
const dimensions = endpoint.getDefaultDimensions(layer.name);
|
|
68
|
+
olLayer.setSource(new WMTS({
|
|
69
|
+
layer: layer.name,
|
|
70
|
+
style: layer.defaultStyle,
|
|
71
|
+
matrixSet: matrixSet.identifier,
|
|
72
|
+
format: resourceUrl.format,
|
|
73
|
+
url: resourceUrl.url,
|
|
74
|
+
requestEncoding: resourceUrl.encoding,
|
|
75
|
+
tileGrid,
|
|
76
|
+
projection: matrixSet.crs,
|
|
77
|
+
dimensions,
|
|
78
|
+
attributions: layerModel.attributions,
|
|
79
|
+
}));
|
|
80
|
+
}));
|
|
81
|
+
return olLayer;
|
|
82
|
+
}
|
|
58
83
|
case "wfs": {
|
|
59
84
|
const olLayer = new VectorLayer({
|
|
60
85
|
style,
|
|
@@ -102,7 +127,7 @@ export function createLayer(layerModel) {
|
|
|
102
127
|
geojson = { type: "FeatureCollection", features: [] };
|
|
103
128
|
}
|
|
104
129
|
}
|
|
105
|
-
const features =
|
|
130
|
+
const features = GEOJSON.readFeatures(geojson, {
|
|
106
131
|
featureProjection: "EPSG:3857",
|
|
107
132
|
dataProjection: "EPSG:4326",
|
|
108
133
|
});
|
|
@@ -120,7 +145,7 @@ export function createLayer(layerModel) {
|
|
|
120
145
|
const ogcEndpoint = yield new OgcApiEndpoint(layerModel.url);
|
|
121
146
|
let layerUrl;
|
|
122
147
|
if (layerModel.useTiles) {
|
|
123
|
-
if (layerModel.useTiles ===
|
|
148
|
+
if (layerModel.useTiles === "vector") {
|
|
124
149
|
layerUrl = yield ogcEndpoint.getVectorTilesetUrl(layerModel.collection, layerModel.tileMatrixSet);
|
|
125
150
|
layer = new VectorTileLayer({
|
|
126
151
|
source: new OGCVectorTile({
|
|
@@ -130,7 +155,7 @@ export function createLayer(layerModel) {
|
|
|
130
155
|
}),
|
|
131
156
|
});
|
|
132
157
|
}
|
|
133
|
-
else if (layerModel.useTiles ===
|
|
158
|
+
else if (layerModel.useTiles === "map") {
|
|
134
159
|
layerUrl = yield ogcEndpoint.getMapTilesetUrl(layerModel.collection, layerModel.tileMatrixSet);
|
|
135
160
|
layer = new TileLayer({
|
|
136
161
|
source: new OGCMapTile({
|
|
@@ -154,7 +179,7 @@ export function createLayer(layerModel) {
|
|
|
154
179
|
break;
|
|
155
180
|
}
|
|
156
181
|
default:
|
|
157
|
-
throw new Error(`Unrecognized layer type: ${layerModel
|
|
182
|
+
throw new Error(`Unrecognized layer type: ${JSON.stringify(layerModel)}`);
|
|
158
183
|
}
|
|
159
184
|
if (!layer) {
|
|
160
185
|
throw new Error(`Layer could not be created for type: ${layerModel.type}`);
|
|
@@ -170,23 +195,26 @@ export function createLayer(layerModel) {
|
|
|
170
195
|
});
|
|
171
196
|
}
|
|
172
197
|
export function createView(viewModel, map) {
|
|
173
|
-
const {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
extent: maxExtent,
|
|
182
|
-
multiWorld: false,
|
|
183
|
-
constrainResolution: true,
|
|
184
|
-
});
|
|
185
|
-
if (viewModel.extent) {
|
|
198
|
+
const view = new View(Object.assign(Object.assign(Object.assign({}, ("maxExtent" in viewModel && { extent: viewModel.maxExtent })), ("maxZoom" in viewModel && { maxZoom: viewModel.maxZoom })), { multiWorld: false, constrainResolution: true }));
|
|
199
|
+
if ("geometry" in viewModel) {
|
|
200
|
+
const geom = GEOJSON.readGeometry(viewModel.geometry);
|
|
201
|
+
view.fit(geom, {
|
|
202
|
+
size: map.getSize(),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
else if ("extent" in viewModel) {
|
|
186
206
|
view.fit(viewModel.extent, {
|
|
187
207
|
size: map.getSize(),
|
|
188
208
|
});
|
|
189
209
|
}
|
|
210
|
+
else {
|
|
211
|
+
const { center: centerInViewProj, zoom } = viewModel;
|
|
212
|
+
const center = centerInViewProj
|
|
213
|
+
? fromLonLat(centerInViewProj, "EPSG:3857")
|
|
214
|
+
: [0, 0];
|
|
215
|
+
view.setCenter(center);
|
|
216
|
+
view.setZoom(zoom !== undefined ? zoom : 0);
|
|
217
|
+
}
|
|
190
218
|
return view;
|
|
191
219
|
}
|
|
192
220
|
/**
|
|
@@ -18,7 +18,7 @@ import { beforeEach } from "vitest";
|
|
|
18
18
|
import BaseLayer from "ol/layer/Base";
|
|
19
19
|
|
|
20
20
|
async function assertEqualsToModel(layer: any, layerModel: MapContextLayer) {
|
|
21
|
-
const reference = await createLayer(layerModel) as any;
|
|
21
|
+
const reference = (await createLayer(layerModel)) as any;
|
|
22
22
|
expect(reference).toBeInstanceOf(layer.constructor);
|
|
23
23
|
const refSource = reference.getSource() as any;
|
|
24
24
|
const layerSource = layer.getSource() as any;
|
|
@@ -235,7 +235,7 @@ describe("applyContextDiffToMap", () => {
|
|
|
235
235
|
describe("combined changes", () => {
|
|
236
236
|
let changedLayer: MapContextLayer;
|
|
237
237
|
beforeEach(async () => {
|
|
238
|
-
changedLayer = {...SAMPLE_LAYER3, extras: {prop: true}};
|
|
238
|
+
changedLayer = { ...SAMPLE_LAYER3, extras: { prop: true } };
|
|
239
239
|
context = {
|
|
240
240
|
...context,
|
|
241
241
|
layers: [SAMPLE_LAYER1, SAMPLE_LAYER5, SAMPLE_LAYER3, SAMPLE_LAYER4],
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import Map from "ol/Map";
|
|
2
2
|
import { MapContextDiff } from "@geospatial-sdk/core";
|
|
3
3
|
import { createLayer } from "./create-map";
|
|
4
|
+
import { fromLonLat, transformExtent } from "ol/proj";
|
|
5
|
+
import GeoJSON from "ol/format/GeoJSON";
|
|
6
|
+
import SimpleGeometry from "ol/geom/SimpleGeometry";
|
|
7
|
+
|
|
8
|
+
const GEOJSON = new GeoJSON();
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* Apply a context diff to an OpenLayers map
|
|
@@ -8,15 +13,15 @@ import { createLayer } from "./create-map";
|
|
|
8
13
|
* @param contextDiff
|
|
9
14
|
*/
|
|
10
15
|
export async function applyContextDiffToMap(
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
map: Map,
|
|
17
|
+
contextDiff: MapContextDiff,
|
|
13
18
|
): Promise<Map> {
|
|
14
19
|
const layers = map.getLayers();
|
|
15
20
|
|
|
16
21
|
// removed layers (sorted by descending position)
|
|
17
22
|
if (contextDiff.layersRemoved.length > 0) {
|
|
18
23
|
const removed = contextDiff.layersRemoved.sort(
|
|
19
|
-
|
|
24
|
+
(a, b) => b.position - a.position,
|
|
20
25
|
);
|
|
21
26
|
for (const layerRemoved of removed) {
|
|
22
27
|
layers.item(layerRemoved.position).dispose();
|
|
@@ -26,7 +31,7 @@ export async function applyContextDiffToMap(
|
|
|
26
31
|
|
|
27
32
|
// insert added layers
|
|
28
33
|
const newLayers = await Promise.all(
|
|
29
|
-
|
|
34
|
+
contextDiff.layersAdded.map((layerAdded) => createLayer(layerAdded.layer)),
|
|
30
35
|
);
|
|
31
36
|
|
|
32
37
|
newLayers.forEach((layer, index) => {
|
|
@@ -41,10 +46,10 @@ export async function applyContextDiffToMap(
|
|
|
41
46
|
// move reordered layers (sorted by ascending new position)
|
|
42
47
|
if (contextDiff.layersReordered.length > 0) {
|
|
43
48
|
const reordered = contextDiff.layersReordered.sort(
|
|
44
|
-
|
|
49
|
+
(a, b) => a.newPosition - b.newPosition,
|
|
45
50
|
);
|
|
46
51
|
const olLayers = reordered.map((layer) =>
|
|
47
|
-
|
|
52
|
+
layers.item(layer.previousPosition),
|
|
48
53
|
);
|
|
49
54
|
const layersArray = layers.getArray();
|
|
50
55
|
for (let i = 0; i < reordered.length; i++) {
|
|
@@ -56,9 +61,45 @@ export async function applyContextDiffToMap(
|
|
|
56
61
|
// recreate changed layers
|
|
57
62
|
for (const layerChanged of contextDiff.layersChanged) {
|
|
58
63
|
layers.item(layerChanged.position).dispose();
|
|
59
|
-
createLayer(layerChanged.layer).then(layer => {
|
|
64
|
+
createLayer(layerChanged.layer).then((layer) => {
|
|
60
65
|
layers.setAt(layerChanged.position, layer);
|
|
61
66
|
});
|
|
62
67
|
}
|
|
68
|
+
|
|
69
|
+
if ("viewChanges" in contextDiff) {
|
|
70
|
+
const { viewChanges } = contextDiff;
|
|
71
|
+
const view = map.getView();
|
|
72
|
+
const projection = view.getProjection();
|
|
73
|
+
if (!viewChanges) {
|
|
74
|
+
return map;
|
|
75
|
+
}
|
|
76
|
+
if ("geometry" in viewChanges) {
|
|
77
|
+
const geom = GEOJSON.readGeometry(viewChanges.geometry);
|
|
78
|
+
view.fit(geom as SimpleGeometry, {
|
|
79
|
+
size: map.getSize(),
|
|
80
|
+
});
|
|
81
|
+
} else if ("extent" in viewChanges) {
|
|
82
|
+
view.fit(transformExtent(viewChanges.extent, "EPSG:4326", projection), {
|
|
83
|
+
size: map.getSize(),
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
const { center: centerInViewProj, zoom } = viewChanges;
|
|
87
|
+
const center = centerInViewProj
|
|
88
|
+
? fromLonLat(centerInViewProj, projection)
|
|
89
|
+
: [0, 0];
|
|
90
|
+
view.setCenter(center);
|
|
91
|
+
view.setZoom(zoom);
|
|
92
|
+
if (viewChanges.maxZoom) {
|
|
93
|
+
view.setMaxZoom(viewChanges.maxZoom);
|
|
94
|
+
}
|
|
95
|
+
// TODO: factorize this better
|
|
96
|
+
// if (viewChanges.maxExtent) {
|
|
97
|
+
// map.setView(new View({
|
|
98
|
+
//
|
|
99
|
+
// }))
|
|
100
|
+
// }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
63
104
|
return map;
|
|
64
105
|
}
|
|
@@ -12,10 +12,11 @@ import {
|
|
|
12
12
|
MAP_CTX_FIXTURE,
|
|
13
13
|
MAP_CTX_LAYER_GEOJSON_FIXTURE,
|
|
14
14
|
MAP_CTX_LAYER_GEOJSON_REMOTE_FIXTURE,
|
|
15
|
+
MAP_CTX_LAYER_OGCAPI_FIXTURE,
|
|
15
16
|
MAP_CTX_LAYER_WFS_FIXTURE,
|
|
16
17
|
MAP_CTX_LAYER_WMS_FIXTURE,
|
|
18
|
+
MAP_CTX_LAYER_WMTS_FIXTURE,
|
|
17
19
|
MAP_CTX_LAYER_XYZ_FIXTURE,
|
|
18
|
-
MAP_CTX_LAYER_OGCAPI_FIXTURE,
|
|
19
20
|
} from "@geospatial-sdk/core/fixtures/map-context.fixtures";
|
|
20
21
|
import {
|
|
21
22
|
MapContext,
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
createView,
|
|
31
32
|
resetMapFromContext,
|
|
32
33
|
} from "./create-map";
|
|
34
|
+
import WMTS from "ol/source/WMTS";
|
|
33
35
|
|
|
34
36
|
describe("MapContextService", () => {
|
|
35
37
|
describe("#createLayer", () => {
|
|
@@ -64,36 +66,36 @@ describe("MapContextService", () => {
|
|
|
64
66
|
});
|
|
65
67
|
});
|
|
66
68
|
describe("OGCAPI", () => {
|
|
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
|
-
|
|
69
|
+
beforeEach(async () => {
|
|
70
|
+
layerModel = MAP_CTX_LAYER_OGCAPI_FIXTURE;
|
|
71
|
+
layer = await createLayer(layerModel);
|
|
72
|
+
});
|
|
73
|
+
it("create a vector tile layer", () => {
|
|
74
|
+
expect(layer).toBeTruthy();
|
|
75
|
+
expect(layer).toBeInstanceOf(VectorLayer);
|
|
76
|
+
});
|
|
77
|
+
it("set correct layer properties", () => {
|
|
78
|
+
expect(layer.getVisible()).toBe(true);
|
|
79
|
+
expect(layer.getOpacity()).toBe(1);
|
|
80
|
+
expect(layer.get("label")).toBeUndefined();
|
|
81
|
+
expect(layer.getSource()?.getAttributions()).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
it("create a OGCVectorTile source", () => {
|
|
84
|
+
const source = layer.getSource();
|
|
85
|
+
expect(source).toBeInstanceOf(VectorSource);
|
|
86
|
+
});
|
|
87
|
+
it("set correct url", () => {
|
|
88
|
+
const source = layer.getSource() as VectorSource;
|
|
89
|
+
const url = source.getUrl();
|
|
90
|
+
expect(url).toBe(
|
|
91
|
+
"https://demo.ldproxy.net/zoomstack/collections/airports/items?f=json",
|
|
92
|
+
);
|
|
93
|
+
});
|
|
92
94
|
});
|
|
93
95
|
describe("WMS", () => {
|
|
94
96
|
beforeEach(async () => {
|
|
95
97
|
(layerModel = MAP_CTX_LAYER_WMS_FIXTURE),
|
|
96
|
-
|
|
98
|
+
(layer = await createLayer(layerModel));
|
|
97
99
|
});
|
|
98
100
|
it("create a tile layer", () => {
|
|
99
101
|
expect(layer).toBeTruthy();
|
|
@@ -133,7 +135,7 @@ describe("MapContextService", () => {
|
|
|
133
135
|
describe("WFS", () => {
|
|
134
136
|
beforeEach(async () => {
|
|
135
137
|
(layerModel = MAP_CTX_LAYER_WFS_FIXTURE),
|
|
136
|
-
|
|
138
|
+
(layer = await createLayer(layerModel));
|
|
137
139
|
});
|
|
138
140
|
it("create a vector layer", () => {
|
|
139
141
|
expect(layer).toBeTruthy();
|
|
@@ -193,7 +195,7 @@ describe("MapContextService", () => {
|
|
|
193
195
|
});
|
|
194
196
|
describe("with inline data as string", () => {
|
|
195
197
|
beforeEach(async () => {
|
|
196
|
-
layerModel = {...MAP_CTX_LAYER_GEOJSON_FIXTURE};
|
|
198
|
+
layerModel = { ...MAP_CTX_LAYER_GEOJSON_FIXTURE };
|
|
197
199
|
layerModel.data = JSON.stringify(layerModel.data);
|
|
198
200
|
layer = await createLayer(layerModel);
|
|
199
201
|
});
|
|
@@ -261,6 +263,34 @@ describe("MapContextService", () => {
|
|
|
261
263
|
});
|
|
262
264
|
});
|
|
263
265
|
});
|
|
266
|
+
|
|
267
|
+
describe("WMTS", () => {
|
|
268
|
+
beforeEach(async () => {
|
|
269
|
+
(layerModel = MAP_CTX_LAYER_WMTS_FIXTURE),
|
|
270
|
+
(layer = await createLayer(layerModel));
|
|
271
|
+
});
|
|
272
|
+
it("create a tile layer", () => {
|
|
273
|
+
expect(layer).toBeTruthy();
|
|
274
|
+
expect(layer).toBeInstanceOf(TileLayer);
|
|
275
|
+
});
|
|
276
|
+
it("set correct layer properties", () => {
|
|
277
|
+
expect(layer.getVisible()).toBe(true);
|
|
278
|
+
expect(layer.getOpacity()).toBe(1);
|
|
279
|
+
expect(layer.get("label")).toBeUndefined();
|
|
280
|
+
expect(layer.getSource()?.getAttributions()).toBeNull();
|
|
281
|
+
});
|
|
282
|
+
it("create a WMTS source", () => {
|
|
283
|
+
const source = layer.getSource();
|
|
284
|
+
expect(source).toBeInstanceOf(WMTS);
|
|
285
|
+
});
|
|
286
|
+
it("set correct urls", () => {
|
|
287
|
+
const source = layer.getSource() as WMTS;
|
|
288
|
+
const urls = source.getUrls() ?? [];
|
|
289
|
+
expect(urls).toEqual([
|
|
290
|
+
"https://services.geo.sg.ch/wss/service/SG00066_WMTS/guest/tile/1.0.0/SG00066/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}",
|
|
291
|
+
]);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
264
294
|
});
|
|
265
295
|
|
|
266
296
|
describe("#createView", () => {
|
package/lib/map/create-map.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
MapContext,
|
|
3
3
|
MapContextLayer,
|
|
4
4
|
MapContextView,
|
|
5
|
+
removeSearchParams,
|
|
5
6
|
} from "@geospatial-sdk/core";
|
|
6
7
|
import Map from "ol/Map";
|
|
7
8
|
import View from "ol/View";
|
|
@@ -14,16 +15,20 @@ import VectorSource from "ol/source/Vector";
|
|
|
14
15
|
import GeoJSON from "ol/format/GeoJSON";
|
|
15
16
|
import Feature from "ol/Feature";
|
|
16
17
|
import Geometry from "ol/geom/Geometry";
|
|
18
|
+
import SimpleGeometry from "ol/geom/SimpleGeometry";
|
|
17
19
|
import { fromLonLat } from "ol/proj";
|
|
18
20
|
import { bbox as bboxStrategy } from "ol/loadingstrategy";
|
|
19
|
-
import { removeSearchParams } from "@geospatial-sdk/core";
|
|
20
21
|
import { defaultStyle } from "./styles";
|
|
21
22
|
import VectorTileLayer from "ol/layer/VectorTile";
|
|
22
|
-
import {OGCMapTile, OGCVectorTile} from "ol/source";
|
|
23
|
-
import {MVT} from "ol/format";
|
|
24
|
-
import {
|
|
23
|
+
import { OGCMapTile, OGCVectorTile, WMTS } from "ol/source";
|
|
24
|
+
import { MVT } from "ol/format";
|
|
25
|
+
import {
|
|
26
|
+
OgcApiEndpoint,
|
|
27
|
+
WfsEndpoint,
|
|
28
|
+
WmtsEndpoint,
|
|
29
|
+
} from "@camptocamp/ogc-client";
|
|
25
30
|
|
|
26
|
-
const
|
|
31
|
+
const GEOJSON = new GeoJSON();
|
|
27
32
|
const WFS_MAX_FEATURES = 10000;
|
|
28
33
|
|
|
29
34
|
export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
@@ -49,33 +54,59 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
49
54
|
}),
|
|
50
55
|
});
|
|
51
56
|
break;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
case "wmts": {
|
|
58
|
+
const olLayer = new TileLayer({});
|
|
59
|
+
const endpoint = new WmtsEndpoint(layerModel.url);
|
|
60
|
+
endpoint.isReady().then(async (endpoint) => {
|
|
61
|
+
const layerName = endpoint.getSingleLayerName() ?? layerModel.name;
|
|
62
|
+
const layer = endpoint.getLayerByName(layerName);
|
|
63
|
+
const matrixSet = layer.matrixSets[0];
|
|
64
|
+
const tileGrid = await endpoint.getOpenLayersTileGrid(layer.name);
|
|
65
|
+
if (tileGrid === null) {
|
|
66
|
+
console.warn("A WMTS tile grid could not be created", layerModel);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const resourceUrl = layer.resourceLinks[0];
|
|
70
|
+
const dimensions = endpoint.getDefaultDimensions(layer.name);
|
|
71
|
+
olLayer.setSource(
|
|
72
|
+
new WMTS({
|
|
73
|
+
layer: layer.name,
|
|
74
|
+
style: layer.defaultStyle,
|
|
75
|
+
matrixSet: matrixSet.identifier,
|
|
76
|
+
format: resourceUrl.format,
|
|
77
|
+
url: resourceUrl.url,
|
|
78
|
+
requestEncoding: resourceUrl.encoding,
|
|
79
|
+
tileGrid,
|
|
80
|
+
projection: matrixSet.crs,
|
|
81
|
+
dimensions,
|
|
82
|
+
attributions: layerModel.attributions,
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
return olLayer;
|
|
87
|
+
}
|
|
88
|
+
case "wfs": {
|
|
58
89
|
const olLayer = new VectorLayer({
|
|
59
90
|
style,
|
|
60
91
|
});
|
|
61
92
|
new WfsEndpoint(layerModel.url).isReady().then((endpoint) => {
|
|
62
93
|
const featureType =
|
|
63
|
-
|
|
94
|
+
endpoint.getSingleFeatureTypeName() ?? layerModel.featureType;
|
|
64
95
|
olLayer.setSource(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
96
|
+
new VectorSource({
|
|
97
|
+
format: new GeoJSON(),
|
|
98
|
+
url: function (extent) {
|
|
99
|
+
return endpoint.getFeatureUrl(featureType, {
|
|
100
|
+
maxFeatures: WFS_MAX_FEATURES,
|
|
101
|
+
asJson: true,
|
|
102
|
+
outputCrs: "EPSG:3857",
|
|
103
|
+
extent: extent as [number, number, number, number],
|
|
104
|
+
extentCrs: "EPSG:3857",
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
strategy: bboxStrategy,
|
|
108
|
+
attributions: layerModel.attributions,
|
|
109
|
+
}),
|
|
79
110
|
);
|
|
80
111
|
});
|
|
81
112
|
layer = olLayer;
|
|
@@ -101,7 +132,7 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
101
132
|
geojson = { type: "FeatureCollection", features: [] };
|
|
102
133
|
}
|
|
103
134
|
}
|
|
104
|
-
const features =
|
|
135
|
+
const features = GEOJSON.readFeatures(geojson, {
|
|
105
136
|
featureProjection: "EPSG:3857",
|
|
106
137
|
dataProjection: "EPSG:4326",
|
|
107
138
|
}) as Feature<Geometry>[];
|
|
@@ -119,8 +150,11 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
119
150
|
const ogcEndpoint = await new OgcApiEndpoint(layerModel.url);
|
|
120
151
|
let layerUrl: string;
|
|
121
152
|
if (layerModel.useTiles) {
|
|
122
|
-
if (layerModel.useTiles ===
|
|
123
|
-
layerUrl = await ogcEndpoint.getVectorTilesetUrl(
|
|
153
|
+
if (layerModel.useTiles === "vector") {
|
|
154
|
+
layerUrl = await ogcEndpoint.getVectorTilesetUrl(
|
|
155
|
+
layerModel.collection,
|
|
156
|
+
layerModel.tileMatrixSet,
|
|
157
|
+
);
|
|
124
158
|
layer = new VectorTileLayer({
|
|
125
159
|
source: new OGCVectorTile({
|
|
126
160
|
url: layerUrl,
|
|
@@ -128,8 +162,11 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
128
162
|
attributions: layerModel.attributions,
|
|
129
163
|
}),
|
|
130
164
|
});
|
|
131
|
-
} else if (layerModel.useTiles ===
|
|
132
|
-
layerUrl = await ogcEndpoint.getMapTilesetUrl(
|
|
165
|
+
} else if (layerModel.useTiles === "map") {
|
|
166
|
+
layerUrl = await ogcEndpoint.getMapTilesetUrl(
|
|
167
|
+
layerModel.collection,
|
|
168
|
+
layerModel.tileMatrixSet,
|
|
169
|
+
);
|
|
133
170
|
layer = new TileLayer({
|
|
134
171
|
source: new OGCMapTile({
|
|
135
172
|
url: layerUrl,
|
|
@@ -138,7 +175,10 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
138
175
|
});
|
|
139
176
|
}
|
|
140
177
|
} else {
|
|
141
|
-
layerUrl = await ogcEndpoint.getCollectionItemsUrl(
|
|
178
|
+
layerUrl = await ogcEndpoint.getCollectionItemsUrl(
|
|
179
|
+
layerModel.collection,
|
|
180
|
+
layerModel.options,
|
|
181
|
+
);
|
|
142
182
|
layer = new VectorLayer({
|
|
143
183
|
source: new VectorSource({
|
|
144
184
|
format: new GeoJSON(),
|
|
@@ -151,7 +191,7 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
151
191
|
break;
|
|
152
192
|
}
|
|
153
193
|
default:
|
|
154
|
-
throw new Error(`Unrecognized layer type: ${layerModel
|
|
194
|
+
throw new Error(`Unrecognized layer type: ${JSON.stringify(layerModel)}`);
|
|
155
195
|
}
|
|
156
196
|
if (!layer) {
|
|
157
197
|
throw new Error(`Layer could not be created for type: ${layerModel.type}`);
|
|
@@ -168,22 +208,28 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
168
208
|
}
|
|
169
209
|
|
|
170
210
|
export function createView(viewModel: MapContextView, map: Map): View {
|
|
171
|
-
const { center: centerInViewProj, zoom, maxZoom, maxExtent } = viewModel;
|
|
172
|
-
const center = centerInViewProj
|
|
173
|
-
? fromLonLat(centerInViewProj, "EPSG:3857")
|
|
174
|
-
: [0, 0];
|
|
175
211
|
const view = new View({
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
maxZoom,
|
|
179
|
-
extent: maxExtent,
|
|
212
|
+
...("maxExtent" in viewModel && { extent: viewModel.maxExtent }),
|
|
213
|
+
...("maxZoom" in viewModel && { maxZoom: viewModel.maxZoom }),
|
|
180
214
|
multiWorld: false,
|
|
181
215
|
constrainResolution: true,
|
|
182
216
|
});
|
|
183
|
-
if (viewModel
|
|
217
|
+
if ("geometry" in viewModel) {
|
|
218
|
+
const geom = GEOJSON.readGeometry(viewModel.geometry);
|
|
219
|
+
view.fit(geom as SimpleGeometry, {
|
|
220
|
+
size: map.getSize(),
|
|
221
|
+
});
|
|
222
|
+
} else if ("extent" in viewModel) {
|
|
184
223
|
view.fit(viewModel.extent, {
|
|
185
224
|
size: map.getSize(),
|
|
186
225
|
});
|
|
226
|
+
} else {
|
|
227
|
+
const { center: centerInViewProj, zoom } = viewModel;
|
|
228
|
+
const center = centerInViewProj
|
|
229
|
+
? fromLonLat(centerInViewProj, "EPSG:3857")
|
|
230
|
+
: [0, 0];
|
|
231
|
+
view.setCenter(center);
|
|
232
|
+
view.setZoom(zoom !== undefined ? zoom : 0);
|
|
187
233
|
}
|
|
188
234
|
return view;
|
|
189
235
|
}
|
|
@@ -194,8 +240,8 @@ export function createView(viewModel: MapContextView, map: Map): View {
|
|
|
194
240
|
* @param target
|
|
195
241
|
*/
|
|
196
242
|
export async function createMapFromContext(
|
|
197
|
-
|
|
198
|
-
|
|
243
|
+
context: MapContext,
|
|
244
|
+
target?: string | HTMLElement,
|
|
199
245
|
): Promise<Map> {
|
|
200
246
|
const map = new Map({
|
|
201
247
|
target,
|
|
@@ -208,7 +254,10 @@ export async function createMapFromContext(
|
|
|
208
254
|
* @param map
|
|
209
255
|
* @param context
|
|
210
256
|
*/
|
|
211
|
-
export async function resetMapFromContext(
|
|
257
|
+
export async function resetMapFromContext(
|
|
258
|
+
map: Map,
|
|
259
|
+
context: MapContext,
|
|
260
|
+
): Promise<Map> {
|
|
212
261
|
map.setView(createView(context.view, map));
|
|
213
262
|
map.getLayers().clear();
|
|
214
263
|
for (const layerModel of context.layers) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geospatial-sdk/openlayers",
|
|
3
|
-
"version": "0.0.5-dev.
|
|
3
|
+
"version": "0.0.5-dev.15+751c3f3",
|
|
4
4
|
"description": "OpenLayers-related utilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ol",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"ol": ">6.x"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@geospatial-sdk/core": "^0.0.5-dev.
|
|
38
|
+
"@geospatial-sdk/core": "^0.0.5-dev.15+751c3f3",
|
|
39
39
|
"chroma-js": "^2.4.2"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "751c3f38588b76394f9d27d6f76f862f0cff52e2"
|
|
42
42
|
}
|