@geospatial-sdk/openlayers 0.0.5-dev.54 → 0.0.5-dev.56
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 +9 -1
- package/dist/map/create-map.d.ts +1 -1
- package/dist/map/create-map.d.ts.map +1 -1
- package/dist/map/create-map.js +73 -30
- package/dist/map/feature-hover.js +1 -1
- package/dist/map/handle-errors.d.ts +0 -7
- package/dist/map/handle-errors.d.ts.map +1 -1
- package/dist/map/handle-errors.js +10 -14
- package/dist/map/index.d.ts +2 -1
- package/dist/map/index.d.ts.map +1 -1
- package/dist/map/index.js +2 -1
- package/dist/map/layer-update.d.ts.map +1 -1
- package/dist/map/layer-update.js +1 -1
- package/dist/map/listen.d.ts.map +1 -1
- package/dist/map/listen.js +13 -26
- package/dist/map/register-events.d.ts +16 -2
- package/dist/map/register-events.d.ts.map +1 -1
- package/dist/map/register-events.js +172 -81
- package/lib/map/apply-context-diff.ts +16 -5
- package/lib/map/create-map.test.ts +172 -60
- package/lib/map/create-map.ts +100 -37
- package/lib/map/feature-hover.ts +1 -1
- package/lib/map/handle-errors.test.ts +13 -36
- package/lib/map/handle-errors.ts +10 -28
- package/lib/map/index.ts +2 -1
- package/lib/map/layer-update.ts +3 -2
- package/lib/map/listen.test.ts +977 -0
- package/lib/map/listen.ts +123 -0
- package/lib/map/register-events.ts +229 -109
- package/lib/map/resolved-map-state.ts +38 -0
- package/package.json +3 -3
- package/dist/map/feature-selection.d.ts +0 -8
- package/dist/map/feature-selection.d.ts.map +0 -1
- package/dist/map/feature-selection.js +0 -76
- package/dist/map/styles.d.ts +0 -16
- package/dist/map/styles.d.ts.map +0 -1
- package/dist/map/styles.js +0 -77
- package/dist/resolved-state/resolved-map-state.d.ts +0 -2
- package/dist/resolved-state/resolved-map-state.d.ts.map +0 -1
- package/dist/resolved-state/resolved-map-state.js +0 -1
- package/lib/map/register-events.test.ts +0 -259
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import XYZ from "ol/source/XYZ.js";
|
|
8
|
-
import View from "ol/View.js";
|
|
9
|
-
import GeoJSON from "ol/format/GeoJSON.js";
|
|
1
|
+
import {
|
|
2
|
+
MapContext,
|
|
3
|
+
MapContextLayer,
|
|
4
|
+
MapContextLayerGeojson,
|
|
5
|
+
MapContextLayerWms,
|
|
6
|
+
} from "@geospatial-sdk/core";
|
|
10
7
|
import {
|
|
11
8
|
MAP_CTX_EXTENT_FIXTURE,
|
|
12
9
|
MAP_CTX_FIXTURE,
|
|
13
10
|
MAP_CTX_LAYER_GEOJSON_FIXTURE,
|
|
14
11
|
MAP_CTX_LAYER_GEOJSON_REMOTE_FIXTURE,
|
|
12
|
+
MAP_CTX_LAYER_GEOTIFF_FIXTURE,
|
|
15
13
|
MAP_CTX_LAYER_MAPBLIBRE_STYLE_FIXTURE,
|
|
16
14
|
MAP_CTX_LAYER_MVT_FIXTURE,
|
|
17
15
|
MAP_CTX_LAYER_OGCAPI_FIXTURE,
|
|
@@ -20,31 +18,34 @@ import {
|
|
|
20
18
|
MAP_CTX_LAYER_WMTS_FIXTURE,
|
|
21
19
|
MAP_CTX_LAYER_XYZ_FIXTURE,
|
|
22
20
|
} from "@geospatial-sdk/core/fixtures/map-context.fixtures.js";
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} from "@geospatial-sdk/core";
|
|
21
|
+
import { FeatureCollection } from "geojson";
|
|
22
|
+
import { MapboxVectorLayer } from "ol-mapbox-style";
|
|
23
|
+
import { FeatureUrlFunction } from "ol/featureloader.js";
|
|
24
|
+
import GeoJSON from "ol/format/GeoJSON.js";
|
|
25
|
+
import ImageTile from "ol/ImageTile.js";
|
|
29
26
|
import Layer from "ol/layer/Layer.js";
|
|
27
|
+
import TileLayer from "ol/layer/Tile.js";
|
|
28
|
+
import VectorLayer from "ol/layer/Vector.js";
|
|
29
|
+
import VectorTileLayer from "ol/layer/VectorTile.js";
|
|
30
|
+
import WebGLTileLayer from "ol/layer/WebGLTile.js";
|
|
31
|
+
import Map from "ol/Map.js";
|
|
32
|
+
import { VectorTile } from "ol/source.js";
|
|
33
|
+
import GeoTIFF from "ol/source/GeoTIFF.js";
|
|
34
|
+
import TileWMS from "ol/source/TileWMS.js";
|
|
35
|
+
import VectorSource from "ol/source/Vector.js";
|
|
36
|
+
import WMTS from "ol/source/WMTS.js";
|
|
37
|
+
import XYZ from "ol/source/XYZ.js";
|
|
38
|
+
import TileState from "ol/TileState.js";
|
|
39
|
+
import View from "ol/View.js";
|
|
40
|
+
import { beforeEach } from "vitest";
|
|
30
41
|
import {
|
|
31
42
|
createLayer,
|
|
32
43
|
createMapFromContext,
|
|
33
44
|
createView,
|
|
34
45
|
resetMapFromContext,
|
|
35
46
|
} from "./create-map.js";
|
|
36
|
-
import
|
|
37
|
-
import {
|
|
38
|
-
import { MapboxVectorLayer } from "ol-mapbox-style";
|
|
39
|
-
import {
|
|
40
|
-
handleEndpointError,
|
|
41
|
-
tileLoadErrorCatchFunction,
|
|
42
|
-
} from "./handle-errors.js";
|
|
43
|
-
import ImageTile from "ol/ImageTile.js";
|
|
44
|
-
import TileState from "ol/TileState.js";
|
|
45
|
-
import VectorTileLayer from "ol/layer/VectorTile.js";
|
|
46
|
-
import { FeatureUrlFunction } from "ol/featureloader.js";
|
|
47
|
-
import { beforeEach } from "vitest";
|
|
47
|
+
import { tileLoadErrorCatchFunction } from "./handle-errors.js";
|
|
48
|
+
import { GEOSPATIAL_SDK_PREFIX } from "./constants.js";
|
|
48
49
|
|
|
49
50
|
vi.mock("./handle-errors", async (importOriginal) => {
|
|
50
51
|
const actual =
|
|
@@ -56,18 +57,22 @@ vi.mock("./handle-errors", async (importOriginal) => {
|
|
|
56
57
|
};
|
|
57
58
|
});
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
vi.useFakeTimers();
|
|
60
62
|
vi.clearAllMocks();
|
|
61
63
|
});
|
|
62
64
|
|
|
63
65
|
describe("MapContextService", () => {
|
|
64
66
|
describe("#createLayer", () => {
|
|
65
67
|
let layerModel: MapContextLayer, layer: Layer;
|
|
68
|
+
const eventCallback = vi.fn();
|
|
66
69
|
|
|
67
70
|
describe("XYZ", () => {
|
|
68
71
|
beforeEach(async () => {
|
|
69
72
|
layerModel = MAP_CTX_LAYER_XYZ_FIXTURE;
|
|
70
73
|
layer = await createLayer(layerModel);
|
|
74
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
75
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
71
76
|
});
|
|
72
77
|
it("create a tile layer", () => {
|
|
73
78
|
expect(layer).toBeTruthy();
|
|
@@ -105,13 +110,25 @@ describe("MapContextService", () => {
|
|
|
105
110
|
tileLoadFunction(tile, "http://example.com/tile");
|
|
106
111
|
expect(tileLoadErrorCatchFunction).toHaveBeenCalled();
|
|
107
112
|
});
|
|
113
|
+
it("emits a loaded event initially", async () => {
|
|
114
|
+
await vi.runAllTimersAsync();
|
|
115
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
116
|
+
layerState: {
|
|
117
|
+
loaded: true,
|
|
118
|
+
},
|
|
119
|
+
target: layer,
|
|
120
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
108
123
|
});
|
|
109
|
-
describe("OGCAPI", () => {
|
|
124
|
+
describe("OGCAPI (as geojson items)", () => {
|
|
110
125
|
beforeEach(async () => {
|
|
111
126
|
layerModel = MAP_CTX_LAYER_OGCAPI_FIXTURE;
|
|
112
127
|
layer = await createLayer(layerModel);
|
|
128
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
129
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
113
130
|
});
|
|
114
|
-
it("create a vector
|
|
131
|
+
it("create a vector layer", () => {
|
|
115
132
|
expect(layer).toBeTruthy();
|
|
116
133
|
expect(layer).toBeInstanceOf(VectorLayer);
|
|
117
134
|
});
|
|
@@ -121,7 +138,7 @@ describe("MapContextService", () => {
|
|
|
121
138
|
expect(layer.get("label")).toBeUndefined();
|
|
122
139
|
expect(layer.getSource()?.getAttributions()).toBeNull();
|
|
123
140
|
});
|
|
124
|
-
it("create a
|
|
141
|
+
it("create a vector source", () => {
|
|
125
142
|
const source = layer.getSource();
|
|
126
143
|
expect(source).toBeInstanceOf(VectorSource);
|
|
127
144
|
});
|
|
@@ -132,11 +149,23 @@ describe("MapContextService", () => {
|
|
|
132
149
|
"https://demo.ldproxy.net/zoomstack/collections/airports/items?f=json",
|
|
133
150
|
);
|
|
134
151
|
});
|
|
152
|
+
it("emits a loaded event initially", async () => {
|
|
153
|
+
await vi.runAllTimersAsync();
|
|
154
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
155
|
+
layerState: {
|
|
156
|
+
loaded: true,
|
|
157
|
+
},
|
|
158
|
+
target: layer,
|
|
159
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
160
|
+
});
|
|
161
|
+
});
|
|
135
162
|
});
|
|
136
163
|
describe("WMS", () => {
|
|
137
164
|
beforeEach(async () => {
|
|
138
|
-
|
|
139
|
-
|
|
165
|
+
layerModel = MAP_CTX_LAYER_WMS_FIXTURE;
|
|
166
|
+
layer = await createLayer(layerModel);
|
|
167
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
168
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
140
169
|
});
|
|
141
170
|
it("create a tile layer", () => {
|
|
142
171
|
expect(layer).toBeTruthy();
|
|
@@ -186,12 +215,24 @@ describe("MapContextService", () => {
|
|
|
186
215
|
tileLoadFunction(tile, "http://example.com/tile");
|
|
187
216
|
expect(tileLoadErrorCatchFunction).toHaveBeenCalled();
|
|
188
217
|
});
|
|
218
|
+
it("emits a loaded event initially", async () => {
|
|
219
|
+
await vi.runAllTimersAsync();
|
|
220
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
221
|
+
layerState: {
|
|
222
|
+
loaded: true,
|
|
223
|
+
},
|
|
224
|
+
target: layer,
|
|
225
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
226
|
+
});
|
|
227
|
+
});
|
|
189
228
|
});
|
|
190
229
|
|
|
191
230
|
describe("WFS", () => {
|
|
192
231
|
beforeEach(async () => {
|
|
193
|
-
|
|
194
|
-
|
|
232
|
+
layerModel = MAP_CTX_LAYER_WFS_FIXTURE;
|
|
233
|
+
layer = await createLayer(layerModel);
|
|
234
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
235
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
195
236
|
});
|
|
196
237
|
it("create a vector layer", () => {
|
|
197
238
|
expect(layer).toBeTruthy();
|
|
@@ -221,17 +262,15 @@ describe("MapContextService", () => {
|
|
|
221
262
|
"https://www.datagrandest.fr/geoserver/region-grand-est/ows?service=WFS&version=1.1.0&request=GetFeature&outputFormat=application%2Fjson&typename=ms%3Acommune_actuelle_3857&srsname=EPSG%3A3857&bbox=10%2C20%2C30%2C40%2CEPSG%3A3857&maxFeatures=10000",
|
|
222
263
|
);
|
|
223
264
|
});
|
|
224
|
-
it("
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
it("should call handleEndpointError", () => {
|
|
234
|
-
expect(handleEndpointError).toHaveBeenCalled();
|
|
265
|
+
it("emits a loaded event initially", async () => {
|
|
266
|
+
await vi.runAllTimersAsync();
|
|
267
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
268
|
+
layerState: {
|
|
269
|
+
loaded: true,
|
|
270
|
+
},
|
|
271
|
+
target: layer,
|
|
272
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
273
|
+
});
|
|
235
274
|
});
|
|
236
275
|
});
|
|
237
276
|
|
|
@@ -240,6 +279,11 @@ describe("MapContextService", () => {
|
|
|
240
279
|
beforeEach(async () => {
|
|
241
280
|
layerModel = MAP_CTX_LAYER_GEOJSON_FIXTURE;
|
|
242
281
|
layer = await createLayer(layerModel);
|
|
282
|
+
layer.on(
|
|
283
|
+
`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
284
|
+
eventCallback,
|
|
285
|
+
);
|
|
286
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
243
287
|
});
|
|
244
288
|
it("create a VectorLayer", () => {
|
|
245
289
|
expect(layer).toBeTruthy();
|
|
@@ -261,6 +305,16 @@ describe("MapContextService", () => {
|
|
|
261
305
|
.data as FeatureCollection;
|
|
262
306
|
expect(features.length).toBe(data.features.length);
|
|
263
307
|
});
|
|
308
|
+
it("emits a loaded event", async () => {
|
|
309
|
+
await vi.runAllTimersAsync();
|
|
310
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
311
|
+
layerState: {
|
|
312
|
+
loaded: true,
|
|
313
|
+
},
|
|
314
|
+
target: layer,
|
|
315
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
316
|
+
});
|
|
317
|
+
});
|
|
264
318
|
});
|
|
265
319
|
describe("with inline data as string", () => {
|
|
266
320
|
beforeEach(async () => {
|
|
@@ -313,6 +367,11 @@ describe("MapContextService", () => {
|
|
|
313
367
|
beforeEach(async () => {
|
|
314
368
|
layerModel = MAP_CTX_LAYER_GEOJSON_REMOTE_FIXTURE;
|
|
315
369
|
layer = await createLayer(layerModel);
|
|
370
|
+
layer.on(
|
|
371
|
+
`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
372
|
+
eventCallback,
|
|
373
|
+
);
|
|
374
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
316
375
|
});
|
|
317
376
|
it("create a VectorLayer", () => {
|
|
318
377
|
expect(layer).toBeTruthy();
|
|
@@ -332,6 +391,16 @@ describe("MapContextService", () => {
|
|
|
332
391
|
(layerModel as MapContextLayerGeojson).url,
|
|
333
392
|
);
|
|
334
393
|
});
|
|
394
|
+
it("emits a loaded event as well as data info eventually", async () => {
|
|
395
|
+
await vi.runAllTimersAsync();
|
|
396
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
397
|
+
layerState: {
|
|
398
|
+
loaded: true,
|
|
399
|
+
},
|
|
400
|
+
target: layer,
|
|
401
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
402
|
+
});
|
|
403
|
+
});
|
|
335
404
|
});
|
|
336
405
|
});
|
|
337
406
|
|
|
@@ -339,6 +408,8 @@ describe("MapContextService", () => {
|
|
|
339
408
|
beforeEach(async () => {
|
|
340
409
|
layerModel = MAP_CTX_LAYER_WMTS_FIXTURE;
|
|
341
410
|
layer = await createLayer(layerModel);
|
|
411
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
412
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
342
413
|
});
|
|
343
414
|
it("create a tile layer", () => {
|
|
344
415
|
expect(layer).toBeTruthy();
|
|
@@ -363,20 +434,15 @@ describe("MapContextService", () => {
|
|
|
363
434
|
"https://services.geo.sg.ch/wss/service/SG00066_WMTS/guest/tile/1.0.0/SG00066/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}",
|
|
364
435
|
]);
|
|
365
436
|
});
|
|
366
|
-
it("
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
};
|
|
376
|
-
layer = await createLayer(layerModel);
|
|
377
|
-
});
|
|
378
|
-
it("should call handleEndpointError", () => {
|
|
379
|
-
expect(handleEndpointError).toHaveBeenCalled();
|
|
437
|
+
it("emits a loaded event initially", async () => {
|
|
438
|
+
await vi.runAllTimersAsync();
|
|
439
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
440
|
+
layerState: {
|
|
441
|
+
loaded: true,
|
|
442
|
+
},
|
|
443
|
+
target: layer,
|
|
444
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
445
|
+
});
|
|
380
446
|
});
|
|
381
447
|
});
|
|
382
448
|
describe("WMTS without default style given", () => {
|
|
@@ -386,6 +452,8 @@ describe("MapContextService", () => {
|
|
|
386
452
|
url: "https://wmts/no-default-style",
|
|
387
453
|
};
|
|
388
454
|
layer = await createLayer(layerModel);
|
|
455
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
456
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
389
457
|
});
|
|
390
458
|
it("uses the first style as default", async () => {
|
|
391
459
|
const source = layer.getSource() as WMTS;
|
|
@@ -397,6 +465,8 @@ describe("MapContextService", () => {
|
|
|
397
465
|
beforeEach(async () => {
|
|
398
466
|
layerModel = MAP_CTX_LAYER_MAPBLIBRE_STYLE_FIXTURE;
|
|
399
467
|
layer = await createLayer(layerModel);
|
|
468
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
469
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
400
470
|
});
|
|
401
471
|
it("create a tile layer", () => {
|
|
402
472
|
expect(layer).toBeTruthy();
|
|
@@ -411,12 +481,24 @@ describe("MapContextService", () => {
|
|
|
411
481
|
const source = layer.getSource();
|
|
412
482
|
expect(source).toBeInstanceOf(VectorTile);
|
|
413
483
|
});
|
|
484
|
+
it("emits a loaded event initially", async () => {
|
|
485
|
+
await vi.runAllTimersAsync();
|
|
486
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
487
|
+
layerState: {
|
|
488
|
+
loaded: true,
|
|
489
|
+
},
|
|
490
|
+
target: layer,
|
|
491
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
492
|
+
});
|
|
493
|
+
});
|
|
414
494
|
});
|
|
415
495
|
|
|
416
496
|
describe("MVT", () => {
|
|
417
497
|
beforeEach(async () => {
|
|
418
498
|
layerModel = MAP_CTX_LAYER_MVT_FIXTURE;
|
|
419
499
|
layer = await createLayer(layerModel);
|
|
500
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-loading-status`, eventCallback);
|
|
501
|
+
layer.on(`${GEOSPATIAL_SDK_PREFIX}layer-data-info`, eventCallback);
|
|
420
502
|
});
|
|
421
503
|
it("create a VectorTileLayer", () => {
|
|
422
504
|
expect(layer).toBeTruthy();
|
|
@@ -431,6 +513,36 @@ describe("MapContextService", () => {
|
|
|
431
513
|
expect(layer.getOpacity()).toBe(1);
|
|
432
514
|
expect(layer.get("label")).toBeUndefined();
|
|
433
515
|
});
|
|
516
|
+
it("emits a loaded event initially", async () => {
|
|
517
|
+
await vi.runAllTimersAsync();
|
|
518
|
+
expect(eventCallback).toHaveBeenCalledWith({
|
|
519
|
+
layerState: {
|
|
520
|
+
loaded: true,
|
|
521
|
+
},
|
|
522
|
+
target: layer,
|
|
523
|
+
type: `${GEOSPATIAL_SDK_PREFIX}layer-loading-status`,
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
describe("GeoTIFF", () => {
|
|
529
|
+
beforeEach(async () => {
|
|
530
|
+
layerModel = MAP_CTX_LAYER_GEOTIFF_FIXTURE;
|
|
531
|
+
layer = await createLayer(layerModel);
|
|
532
|
+
});
|
|
533
|
+
it("create a WebGLTile layer", () => {
|
|
534
|
+
expect(layer).toBeTruthy();
|
|
535
|
+
expect(layer).toBeInstanceOf(WebGLTileLayer);
|
|
536
|
+
});
|
|
537
|
+
it("set correct layer properties", () => {
|
|
538
|
+
expect(layer.getVisible()).toBe(true);
|
|
539
|
+
expect(layer.getOpacity()).toBe(1);
|
|
540
|
+
expect(layer.get("label")).toBeUndefined();
|
|
541
|
+
});
|
|
542
|
+
it("create a GeoTIFF source", () => {
|
|
543
|
+
const source = layer.getSource();
|
|
544
|
+
expect(source).toBeInstanceOf(GeoTIFF);
|
|
545
|
+
});
|
|
434
546
|
});
|
|
435
547
|
});
|
|
436
548
|
|
package/lib/map/create-map.ts
CHANGED
|
@@ -25,29 +25,48 @@ import OGCVectorTile from "ol/source/OGCVectorTile.js";
|
|
|
25
25
|
import WMTS from "ol/source/WMTS.js";
|
|
26
26
|
import MVT from "ol/format/MVT.js";
|
|
27
27
|
import {
|
|
28
|
+
EndpointError,
|
|
28
29
|
OgcApiEndpoint,
|
|
29
30
|
WfsEndpoint,
|
|
30
31
|
WmtsEndpoint,
|
|
31
32
|
} from "@camptocamp/ogc-client";
|
|
32
33
|
import { MapboxVectorLayer } from "ol-mapbox-style";
|
|
33
34
|
import { Tile } from "ol";
|
|
34
|
-
import {
|
|
35
|
-
handleEndpointError,
|
|
36
|
-
tileLoadErrorCatchFunction,
|
|
37
|
-
} from "./handle-errors.js";
|
|
35
|
+
import { tileLoadErrorCatchFunction } from "./handle-errors.js";
|
|
38
36
|
import VectorTile from "ol/source/VectorTile.js";
|
|
37
|
+
import GeoTIFF from "ol/source/GeoTIFF.js";
|
|
38
|
+
import WebGLTileLayer from "ol/layer/WebGLTile.js";
|
|
39
|
+
import proj4 from "proj4";
|
|
40
|
+
import { register } from "ol/proj/proj4.js";
|
|
39
41
|
import {
|
|
40
42
|
canDoIncrementalUpdate,
|
|
41
43
|
updateLayerProperties,
|
|
42
44
|
} from "./layer-update.js";
|
|
43
45
|
import { initHoverLayer } from "./feature-hover.js";
|
|
46
|
+
import {
|
|
47
|
+
emitLayerCreationError,
|
|
48
|
+
emitLayerLoadingError,
|
|
49
|
+
emitLayerLoadingStatusSuccess,
|
|
50
|
+
propagateLayerStateChangeEventToMap,
|
|
51
|
+
} from "./register-events.js";
|
|
52
|
+
import { GEOSPATIAL_SDK_PREFIX } from "./constants.js";
|
|
53
|
+
|
|
54
|
+
// Register proj4 with OpenLayers so that arbitrary EPSG codes
|
|
55
|
+
// (e.g., UTM zones from GeoTIFF metadata) can be reprojected to the map projection
|
|
56
|
+
register(proj4);
|
|
44
57
|
|
|
45
58
|
const GEOJSON = new GeoJSON();
|
|
46
59
|
const WFS_MAX_FEATURES = 10000;
|
|
47
60
|
|
|
61
|
+
// We need to defer some events being dispatched to make sure they are caught by the map
|
|
62
|
+
// where the layers sit
|
|
63
|
+
// FIXME: this should be better handled in a separate module!
|
|
64
|
+
const defer = () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
65
|
+
|
|
48
66
|
export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
49
67
|
const { type } = layerModel;
|
|
50
|
-
let layer: Layer
|
|
68
|
+
let layer: Layer;
|
|
69
|
+
|
|
51
70
|
switch (type) {
|
|
52
71
|
case "xyz":
|
|
53
72
|
{
|
|
@@ -74,8 +93,10 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
74
93
|
});
|
|
75
94
|
layer.setSource(source);
|
|
76
95
|
}
|
|
96
|
+
defer().then(() => emitLayerLoadingStatusSuccess(layer));
|
|
77
97
|
}
|
|
78
98
|
break;
|
|
99
|
+
|
|
79
100
|
case "wms":
|
|
80
101
|
{
|
|
81
102
|
layer = new TileLayer({});
|
|
@@ -96,9 +117,10 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
96
117
|
);
|
|
97
118
|
});
|
|
98
119
|
layer.setSource(source);
|
|
120
|
+
defer().then(() => emitLayerLoadingStatusSuccess(layer));
|
|
99
121
|
}
|
|
100
|
-
|
|
101
122
|
break;
|
|
123
|
+
|
|
102
124
|
case "wmts": {
|
|
103
125
|
const olLayer = new TileLayer({});
|
|
104
126
|
const endpoint = new WmtsEndpoint(layerModel.url);
|
|
@@ -130,11 +152,16 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
130
152
|
}),
|
|
131
153
|
);
|
|
132
154
|
})
|
|
155
|
+
.then(() => emitLayerLoadingStatusSuccess(olLayer))
|
|
133
156
|
.catch((e) => {
|
|
134
|
-
|
|
157
|
+
const httpStatus =
|
|
158
|
+
e instanceof EndpointError ? e.httpStatus : undefined;
|
|
159
|
+
emitLayerLoadingError(olLayer, e, httpStatus);
|
|
135
160
|
});
|
|
136
|
-
|
|
161
|
+
layer = olLayer;
|
|
162
|
+
break;
|
|
137
163
|
}
|
|
164
|
+
|
|
138
165
|
case "wfs": {
|
|
139
166
|
const olLayer = new VectorLayer({
|
|
140
167
|
style: layerModel.style ?? defaultStyle,
|
|
@@ -161,28 +188,35 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
161
188
|
}),
|
|
162
189
|
);
|
|
163
190
|
})
|
|
191
|
+
.then(() => emitLayerLoadingStatusSuccess(olLayer))
|
|
164
192
|
.catch((e) => {
|
|
165
|
-
|
|
193
|
+
const httpStatus =
|
|
194
|
+
e instanceof EndpointError ? e.httpStatus : undefined;
|
|
195
|
+
emitLayerLoadingError(olLayer, e, httpStatus);
|
|
166
196
|
});
|
|
167
197
|
layer = olLayer;
|
|
168
198
|
break;
|
|
169
199
|
}
|
|
200
|
+
|
|
170
201
|
case "maplibre-style": {
|
|
171
202
|
layer = new MapboxVectorLayer({
|
|
172
203
|
styleUrl: layerModel.styleUrl,
|
|
173
204
|
accessToken: layerModel.accessToken,
|
|
174
205
|
}) as unknown as Layer;
|
|
206
|
+
defer().then(() => emitLayerLoadingStatusSuccess(layer));
|
|
175
207
|
break;
|
|
176
208
|
}
|
|
209
|
+
|
|
177
210
|
case "geojson": {
|
|
211
|
+
layer = new VectorLayer({
|
|
212
|
+
style: layerModel.style ?? defaultStyle,
|
|
213
|
+
});
|
|
214
|
+
let source: VectorSource;
|
|
178
215
|
if (layerModel.url !== undefined) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
attributions: layerModel.attributions,
|
|
184
|
-
}),
|
|
185
|
-
style: layerModel.style ?? defaultStyle,
|
|
216
|
+
source = new VectorSource({
|
|
217
|
+
format: new GeoJSON(),
|
|
218
|
+
url: layerModel.url,
|
|
219
|
+
attributions: layerModel.attributions,
|
|
186
220
|
});
|
|
187
221
|
} else {
|
|
188
222
|
let geojson = layerModel.data;
|
|
@@ -198,16 +232,17 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
198
232
|
featureProjection: "EPSG:3857",
|
|
199
233
|
dataProjection: "EPSG:4326",
|
|
200
234
|
}) as Feature<Geometry>[];
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
attributions: layerModel.attributions,
|
|
205
|
-
}),
|
|
206
|
-
style: layerModel.style ?? defaultStyle,
|
|
235
|
+
source = new VectorSource({
|
|
236
|
+
features,
|
|
237
|
+
attributions: layerModel.attributions,
|
|
207
238
|
});
|
|
208
239
|
}
|
|
240
|
+
layer.setSource(source);
|
|
241
|
+
// FIXME: actually track layer loading and data info
|
|
242
|
+
defer().then(() => emitLayerLoadingStatusSuccess(layer));
|
|
209
243
|
break;
|
|
210
244
|
}
|
|
245
|
+
|
|
211
246
|
case "ogcapi": {
|
|
212
247
|
const ogcEndpoint = new OgcApiEndpoint(layerModel.url);
|
|
213
248
|
let layerUrl: string;
|
|
@@ -241,35 +276,61 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
241
276
|
layerModel.collection,
|
|
242
277
|
layerModel.options,
|
|
243
278
|
);
|
|
279
|
+
const source = new VectorSource({
|
|
280
|
+
format: new GeoJSON(),
|
|
281
|
+
url: layerUrl,
|
|
282
|
+
attributions: layerModel.attributions,
|
|
283
|
+
});
|
|
244
284
|
layer = new VectorLayer({
|
|
245
|
-
source
|
|
246
|
-
format: new GeoJSON(),
|
|
247
|
-
url: layerUrl,
|
|
248
|
-
attributions: layerModel.attributions,
|
|
249
|
-
}),
|
|
285
|
+
source,
|
|
250
286
|
style: layerModel.style ?? defaultStyle,
|
|
251
287
|
});
|
|
252
288
|
}
|
|
289
|
+
// FIXME: actually track layer loading
|
|
290
|
+
defer().then(() => emitLayerLoadingStatusSuccess(layer));
|
|
253
291
|
break;
|
|
254
292
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
293
|
+
|
|
294
|
+
case "geotiff": {
|
|
295
|
+
const geoTiffSource = new GeoTIFF({
|
|
296
|
+
sources: [{ url: layerModel.url }],
|
|
297
|
+
convertToRGB: "auto",
|
|
298
|
+
});
|
|
299
|
+
layer = new WebGLTileLayer({
|
|
300
|
+
source: geoTiffSource,
|
|
301
|
+
});
|
|
302
|
+
// FIXME: actually track tile loading
|
|
303
|
+
defer().then(() => emitLayerLoadingStatusSuccess(layer));
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
default: {
|
|
308
|
+
// we create an empty placeholder layer so that we still have a corresponding layer in OL
|
|
309
|
+
layer = new VectorLayer({
|
|
310
|
+
properties: {
|
|
311
|
+
[`${GEOSPATIAL_SDK_PREFIX}layer-with-error`]: true,
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
defer().then(() =>
|
|
315
|
+
emitLayerCreationError(
|
|
316
|
+
layer,
|
|
317
|
+
new Error(`Unrecognized layer type: ${JSON.stringify(layerModel)}`),
|
|
318
|
+
),
|
|
319
|
+
);
|
|
320
|
+
}
|
|
260
321
|
}
|
|
261
322
|
|
|
262
|
-
updateLayerProperties(layerModel, layer);
|
|
323
|
+
updateLayerProperties(layerModel, layer!);
|
|
263
324
|
|
|
264
|
-
return layer
|
|
325
|
+
return layer!;
|
|
265
326
|
}
|
|
266
327
|
|
|
267
|
-
export function updateLayerInMap(
|
|
328
|
+
export async function updateLayerInMap(
|
|
268
329
|
map: Map,
|
|
269
330
|
layerModel: MapContextLayer,
|
|
270
331
|
layerPosition: number,
|
|
271
332
|
previousLayerModel: MapContextLayer,
|
|
272
|
-
) {
|
|
333
|
+
): Promise<void> {
|
|
273
334
|
const layers = map.getLayers();
|
|
274
335
|
const updatedLayer = layers.item(layerPosition) as Layer;
|
|
275
336
|
|
|
@@ -281,8 +342,9 @@ export function updateLayerInMap(
|
|
|
281
342
|
|
|
282
343
|
// dispose and recreate layer
|
|
283
344
|
updatedLayer.dispose();
|
|
284
|
-
createLayer(layerModel).then((layer) => {
|
|
345
|
+
await createLayer(layerModel).then((layer) => {
|
|
285
346
|
layers.setAt(layerPosition, layer);
|
|
347
|
+
propagateLayerStateChangeEventToMap(map, layer);
|
|
286
348
|
});
|
|
287
349
|
}
|
|
288
350
|
|
|
@@ -351,6 +413,7 @@ export async function resetMapFromContext(
|
|
|
351
413
|
for (const layerModel of context.layers) {
|
|
352
414
|
const layer = await createLayer(layerModel);
|
|
353
415
|
map.addLayer(layer);
|
|
416
|
+
propagateLayerStateChangeEventToMap(map, layer);
|
|
354
417
|
}
|
|
355
418
|
initHoverLayer(map);
|
|
356
419
|
return map;
|
package/lib/map/feature-hover.ts
CHANGED
|
@@ -108,7 +108,7 @@ export function initHoverLayer(map: OlMap) {
|
|
|
108
108
|
);
|
|
109
109
|
const features = Array.from(featuresByLayer.values()).flat();
|
|
110
110
|
map.dispatchEvent({
|
|
111
|
-
type: FeaturesHoverEventType
|
|
111
|
+
type: `${GEOSPATIAL_SDK_PREFIX}${FeaturesHoverEventType}`,
|
|
112
112
|
features,
|
|
113
113
|
featuresByLayer,
|
|
114
114
|
} as unknown as BaseEvent);
|