@geospatial-sdk/maplibre 0.0.5-dev.48 → 0.0.5-dev.50

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.
@@ -1,13 +1,60 @@
1
- import { MapContextDiff } from "@geospatial-sdk/core";
2
- import { Map } from "maplibre-gl";
1
+ import { MapContextDiff, MapContextLayer } from "@geospatial-sdk/core";
2
+ import type { Map } from "maplibre-gl";
3
3
  import { createLayer } from "./create-map.js";
4
4
  import {
5
- generateLayerId,
6
- getBeforeId,
5
+ canDoIncrementalUpdate,
6
+ getFirstLayerIdAtPosition,
7
7
  getLayersAtPosition,
8
- removeLayersFromSource,
8
+ getLayersFromContextLayer,
9
+ updateLayerProperties,
9
10
  } from "../helpers/map.helpers.js";
10
11
 
12
+ /**
13
+ * This will either update the layers in the map or recreate them;
14
+ * the returned promise resolves when the update is done
15
+ * @param map
16
+ * @param layerModel
17
+ * @param previousLayerModel
18
+ * @param layerPosition
19
+ */
20
+ export async function updateLayerInMap(
21
+ map: Map,
22
+ layerModel: MapContextLayer,
23
+ previousLayerModel: MapContextLayer,
24
+ layerPosition: number,
25
+ ): Promise<void> {
26
+ // if an incremental update is possible, do it to avoid costly layer recreation
27
+ if (canDoIncrementalUpdate(previousLayerModel, layerModel)) {
28
+ // we can find the existing layers by using the hash or id of the layerModel
29
+ const mlUpdatedLayers = getLayersFromContextLayer(map, layerModel);
30
+ for (const layer of mlUpdatedLayers) {
31
+ updateLayerProperties(map, layer, layerModel, previousLayerModel);
32
+ }
33
+ return;
34
+ }
35
+
36
+ const mlLayersToRemove = getLayersAtPosition(map, layerPosition);
37
+ const sourcesToRemove: string[] = [];
38
+ for (const layer of mlLayersToRemove) {
39
+ if (layer.source && !sourcesToRemove.includes(layer.source)) {
40
+ sourcesToRemove.push(layer.source);
41
+ }
42
+ map.removeLayer(layer.id);
43
+ }
44
+ for (const sourceId of sourcesToRemove) {
45
+ map.removeSource(sourceId);
46
+ }
47
+ const styleDiff = await createLayer(layerModel);
48
+ if (!styleDiff) return;
49
+ const beforeId = getFirstLayerIdAtPosition(map, layerPosition);
50
+ Object.keys(styleDiff.sources).forEach((sourceId) =>
51
+ map.addSource(sourceId, styleDiff.sources[sourceId]),
52
+ );
53
+ styleDiff.layers.map((layer) => {
54
+ map.addLayer(layer, beforeId);
55
+ });
56
+ }
57
+
11
58
  /**
12
59
  * Apply a context diff to an MapLibre map
13
60
  * @param map
@@ -16,14 +63,14 @@ import {
16
63
  export async function applyContextDiffToMap(
17
64
  map: Map,
18
65
  contextDiff: MapContextDiff,
19
- ): Promise<void> {
66
+ ): Promise<Map> {
20
67
  // removed layers (sorted by descending position)
21
68
  if (contextDiff.layersRemoved.length > 0) {
22
69
  const removed = contextDiff.layersRemoved.sort(
23
70
  (a, b) => b.position - a.position,
24
71
  );
25
72
  for (const layerRemoved of removed) {
26
- const mlLayers = getLayersAtPosition(map, layerRemoved.position);
73
+ const mlLayers = getLayersFromContextLayer(map, layerRemoved.layer);
27
74
  if (mlLayers.length === 0) {
28
75
  console.warn(
29
76
  `[Warning] applyContextDiffToMap: no layer found at position ${layerRemoved.position} to remove.`,
@@ -40,32 +87,56 @@ export async function applyContextDiffToMap(
40
87
 
41
88
  // insert added layers
42
89
  const newLayers = await Promise.all(
43
- contextDiff.layersAdded.map((layerAdded) =>
44
- createLayer(layerAdded.layer, layerAdded.position),
45
- ),
90
+ contextDiff.layersAdded.map((layerAdded) => createLayer(layerAdded.layer)),
46
91
  );
47
- newLayers.forEach((style: any, index: any) => {
92
+ newLayers.forEach((style, index) => {
93
+ if (!style) return;
48
94
  const position = contextDiff.layersAdded[index].position;
49
- const beforeId = getBeforeId(map, position);
95
+ const beforeId = getFirstLayerIdAtPosition(map, position);
50
96
  Object.keys(style.sources).forEach((sourceId) =>
51
97
  map.addSource(sourceId, style.sources[sourceId]),
52
98
  );
53
- style.layers.map((layer: any) => {
99
+ style.layers.map((layer) => {
54
100
  map.addLayer(layer, beforeId);
55
101
  });
56
102
  });
57
103
 
104
+ // handle reordered layers (sorted by ascending new position)
105
+ if (contextDiff.layersReordered.length > 0) {
106
+ const reordered = contextDiff.layersReordered.sort(
107
+ (a, b) => a.newPosition - b.newPosition,
108
+ );
109
+
110
+ // collect all layers to be moved
111
+ const mlLayersToMove = reordered.map((layerReordered) =>
112
+ getLayersFromContextLayer(map, layerReordered.layer),
113
+ );
114
+
115
+ // move layers
116
+ for (let i = 0; i < reordered.length; i++) {
117
+ const layerReordered = reordered[i];
118
+ const mlLayers = mlLayersToMove[i];
119
+ const beforeId = getFirstLayerIdAtPosition(
120
+ map,
121
+ layerReordered.newPosition + 1,
122
+ );
123
+
124
+ if (mlLayers[0].id === beforeId) {
125
+ // layer is already at the right position
126
+ continue;
127
+ }
128
+
129
+ // then we add the moved the layer to its new position
130
+ for (const layer of mlLayers) {
131
+ map.moveLayer(layer.id, beforeId);
132
+ }
133
+ }
134
+ }
135
+
58
136
  // recreate changed layers
59
137
  for (const layerChanged of contextDiff.layersChanged) {
60
- const { layer, position } = layerChanged;
61
- const sourceId = generateLayerId(layer);
62
- removeLayersFromSource(map, sourceId);
63
- const beforeId = getBeforeId(map, position);
64
- createLayer(layer, position).then((styleDiff) => {
65
- styleDiff.layers.map((layer: any) => {
66
- map.addLayer(layer, beforeId);
67
- });
68
- });
138
+ const { layer, previousLayer, position } = layerChanged;
139
+ await updateLayerInMap(map, layer, previousLayer, position);
69
140
  }
70
141
 
71
142
  if (typeof contextDiff.viewChanges !== "undefined") {
@@ -86,4 +157,6 @@ export async function applyContextDiffToMap(
86
157
  );
87
158
  }
88
159
  }
160
+
161
+ return map;
89
162
  }
@@ -5,6 +5,8 @@ import {
5
5
  MAP_CTX_LAYER_OGCAPI_FIXTURE,
6
6
  MAP_CTX_LAYER_WFS_FIXTURE,
7
7
  MAP_CTX_LAYER_WMS_FIXTURE,
8
+ MAP_CTX_LAYER_WMTS_FIXTURE,
9
+ MAP_CTX_LAYER_XYZ_FIXTURE,
8
10
  } from "@geospatial-sdk/core/fixtures/map-context.fixtures.js";
9
11
  import { LayerGeojsonWithData, MapContextLayer } from "@geospatial-sdk/core";
10
12
  import { createLayer } from "./create-map.js";
@@ -13,14 +15,13 @@ import {
13
15
  GeoJSONSourceSpecification,
14
16
  RasterLayerSpecification,
15
17
  } from "@maplibre/maplibre-gl-style-spec";
18
+ import { FEATURE_COLLECTION_POLYGON_FIXTURE_4326 } from "@geospatial-sdk/core/fixtures/geojson.fixtures.js";
16
19
  import {
17
- FEATURE_COLLECTION_LINESTRING_FIXTURE_4326,
18
- FEATURE_COLLECTION_POLYGON_FIXTURE_4326,
19
- } from "@geospatial-sdk/core/fixtures/geojson.fixtures.js";
20
- import { PartialStyleSpecification } from "../maplibre.models.js";
20
+ LayerMetadataSpecification,
21
+ PartialStyleSpecification,
22
+ } from "../maplibre.models.js";
21
23
  import {
22
24
  CircleLayerSpecification,
23
- LayerSpecification,
24
25
  LineLayerSpecification,
25
26
  RasterSourceSpecification,
26
27
  } from "maplibre-gl";
@@ -29,10 +30,15 @@ describe("MapContextService", () => {
29
30
  describe("#createLayer", () => {
30
31
  let layerModel: MapContextLayer, style: PartialStyleSpecification;
31
32
 
33
+ beforeEach(() => {
34
+ // This makes it so that every layerId/sourceId will be "123456"
35
+ vi.spyOn(Math, "random").mockReturnValue(0.123456);
36
+ });
37
+
32
38
  describe("WMS", () => {
33
39
  beforeEach(async () => {
34
- (layerModel = MAP_CTX_LAYER_WMS_FIXTURE),
35
- (style = await createLayer(layerModel, 0));
40
+ layerModel = MAP_CTX_LAYER_WMS_FIXTURE;
41
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
36
42
  });
37
43
  it("create a tile layer", () => {
38
44
  expect(style).toBeTruthy();
@@ -42,7 +48,7 @@ describe("MapContextService", () => {
42
48
  expect(sourcesIds.length).toBe(1);
43
49
  const id = sourcesIds[0];
44
50
  const source = style.sources[id] as RasterSourceSpecification;
45
- expect(id).toBe("1046815418");
51
+ expect(id).toBe("123456");
46
52
  expect(source.tiles).toEqual([
47
53
  "https://www.datagrandest.fr/geoserver/region-grand-est/ows?REQUEST=GetMap&SERVICE=WMS&layers=commune_actuelle_3857&styles=&format=image%2Fpng&transparent=true&version=1.1.1&height=256&width=256&srs=EPSG%3A3857&BBOX={bbox-epsg-3857}",
48
54
  ]);
@@ -52,17 +58,36 @@ describe("MapContextService", () => {
52
58
  expect(style.layers.length).toBe(1);
53
59
 
54
60
  const layer = style.layers[0] as RasterLayerSpecification;
55
- expect(layer.id).toBe("1046815418");
56
- expect(layer.source).toBe("1046815418");
57
- expect(layer.type).toBe(`raster`);
61
+ const metadata = layer.metadata as LayerMetadataSpecification;
62
+
63
+ expect(layer.id).toBe("123456");
64
+ expect(layer.type).toBe("raster");
65
+ expect(layer.source).toBe(layer.id);
66
+ expect(metadata.layerId).toBeUndefined();
67
+ expect(metadata.layerHash).toBeTypeOf("string");
68
+ expect(layer.paint?.["raster-opacity"]).toBe(0.5);
69
+ expect(layer.layout?.visibility).toBe("none");
70
+ });
71
+
72
+ describe("with an id", () => {
73
+ beforeEach(async () => {
74
+ layerModel = { ...MAP_CTX_LAYER_WMS_FIXTURE, id: "my-test-layer" };
75
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
76
+ });
77
+ it("create a layer with layer id in metadata", () => {
78
+ const layer = style.layers[0] as RasterLayerSpecification;
79
+ const metadata = layer.metadata as LayerMetadataSpecification;
80
+ expect(metadata.layerHash).toBeUndefined();
81
+ expect(metadata.layerId).toBe("my-test-layer");
82
+ });
58
83
  });
59
84
  });
85
+
60
86
  describe("GEOJSON", () => {
61
87
  describe("with inline data", () => {
62
88
  beforeEach(async () => {
63
89
  layerModel = MAP_CTX_LAYER_GEOJSON_FIXTURE;
64
- style = await createLayer(layerModel, 0);
65
- Math.random = vi.fn(() => 0.027404);
90
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
66
91
  });
67
92
  it("create a VectorLayer", () => {
68
93
  expect(style).toBeTruthy();
@@ -70,23 +95,35 @@ describe("MapContextService", () => {
70
95
  it("create a source", () => {
71
96
  const sourcesIds = Object.keys(style.sources);
72
97
  expect(sourcesIds.length).toBe(1);
73
- expect(sourcesIds[0]).toBe("2792250259");
98
+ expect(sourcesIds[0]).toBe("123456");
74
99
  });
75
100
  it("create 3 layers", () => {
76
101
  expect(style.layers).toBeTruthy();
77
102
  expect(style.layers.length).toBe(3);
78
103
 
79
- let layer = style.layers[0] as RasterLayerSpecification;
80
- expect(layer.id).toBe("2792250259-fill");
81
- expect(layer.source).toBe("2792250259");
104
+ const sourceId = "123456";
105
+ const fillLayer = style.layers[0] as FillLayerSpecification;
106
+ const metadata = fillLayer.metadata as LayerMetadataSpecification;
82
107
 
83
- layer = style.layers[1] as RasterLayerSpecification;
84
- expect(layer.id).toBe("2792250259-line");
85
- expect(layer.source).toBe("2792250259");
108
+ expect(fillLayer.id).toBe(`${sourceId}-fill`);
109
+ expect(fillLayer.source).toBe(sourceId);
110
+ expect(metadata.layerId).toBeUndefined();
111
+ expect(metadata.layerHash).toBeTypeOf("string");
112
+ expect(fillLayer.paint?.["fill-opacity"]).toBe(0.8);
113
+ expect(fillLayer.layout?.visibility).toBe("visible");
86
114
 
87
- layer = style.layers[2] as RasterLayerSpecification;
88
- expect(layer.id).toBe("2792250259-circle");
89
- expect(layer.source).toBe("2792250259");
115
+ const lineLayer = style.layers[1] as LineLayerSpecification;
116
+ expect(lineLayer.id).toBe(`${sourceId}-line`);
117
+ expect(lineLayer.source).toBe(sourceId);
118
+ expect(lineLayer.paint?.["line-opacity"]).toBe(0.8);
119
+ expect(lineLayer.layout?.visibility).toBe("visible");
120
+
121
+ const circleLayer = style.layers[2] as CircleLayerSpecification;
122
+ expect(circleLayer.id).toBe(`${sourceId}-circle`);
123
+ expect(circleLayer.source).toBe(sourceId);
124
+ expect(circleLayer.paint?.["circle-opacity"]).toBe(0.8);
125
+ expect(circleLayer.paint?.["circle-stroke-opacity"]).toBe(0.8);
126
+ expect(circleLayer.layout?.visibility).toBe("visible");
90
127
  });
91
128
 
92
129
  it("set correct source properties", () => {
@@ -100,14 +137,15 @@ describe("MapContextService", () => {
100
137
  it("set correct layer properties", () => {
101
138
  const layer = style.layers[0] as FillLayerSpecification;
102
139
  expect(layer.type).toBe(`fill`);
103
- expect(layer.paint["fill-color"]).toBe("rgba(255,255,255,0.4)");
140
+ expect(layer.paint?.["fill-color"]).toBe("rgba(255,255,255,0.4)");
141
+ expect(layer.paint?.["fill-opacity"]).toBe(0.8);
104
142
  });
105
143
  });
106
144
  describe("with inline data as string", () => {
107
145
  beforeEach(async () => {
108
146
  layerModel = { ...MAP_CTX_LAYER_GEOJSON_FIXTURE };
109
147
  layerModel.data = JSON.stringify(layerModel.data);
110
- style = await createLayer(layerModel, 0);
148
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
111
149
  });
112
150
  it("create a VectorLayer", () => {
113
151
  expect(style).toBeTruthy();
@@ -133,8 +171,9 @@ describe("MapContextService", () => {
133
171
  it("set correct layer properties", () => {
134
172
  const layer = style.layers[0] as FillLayerSpecification;
135
173
  expect(layer.type).toBe(`fill`);
136
- expect(layer.paint["fill-color"]).toBe("rgba(255,255,255,0.4)");
137
- expect(layer.paint["fill-opacity"]).toBeUndefined();
174
+ expect(layer.paint?.["fill-color"]).toBe("rgba(255,255,255,0.4)");
175
+ expect(layer.paint?.["fill-opacity"]).toBe(0.8);
176
+ expect(layer.layout?.visibility).toBe("visible");
138
177
  });
139
178
  });
140
179
  describe("with invalid inline data as string", () => {
@@ -146,7 +185,7 @@ describe("MapContextService", () => {
146
185
  url: undefined,
147
186
  data: "blargz",
148
187
  } as LayerGeojsonWithData;
149
- style = await createLayer(layerModel, 0);
188
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
150
189
  });
151
190
  it("create a VectorLayer", () => {
152
191
  expect(style).toBeTruthy();
@@ -156,7 +195,7 @@ describe("MapContextService", () => {
156
195
  });
157
196
  it("create an empty VectorSource source", () => {
158
197
  expect(style.sources).toEqual({
159
- "3631250040": {
198
+ "123456": {
160
199
  data: {
161
200
  features: [],
162
201
  type: "FeatureCollection",
@@ -173,9 +212,9 @@ describe("MapContextService", () => {
173
212
  ok: true,
174
213
  json: () =>
175
214
  Promise.resolve(FEATURE_COLLECTION_POLYGON_FIXTURE_4326),
176
- }),
215
+ } as Response),
177
216
  );
178
- style = await createLayer(layerModel, 0);
217
+ style = (await createLayer(layerModel))!;
179
218
  });
180
219
  it("create a VectorLayer", () => {
181
220
  expect(style).toBeTruthy();
@@ -183,6 +222,7 @@ describe("MapContextService", () => {
183
222
  it("create a source", () => {
184
223
  const sourcesIds = Object.keys(style.sources);
185
224
  expect(sourcesIds.length).toBe(1);
225
+ expect(sourcesIds[0]).toBe("123456");
186
226
  });
187
227
  it("create 3 layers", () => {
188
228
  expect(style.layers).toBeTruthy();
@@ -203,16 +243,18 @@ describe("MapContextService", () => {
203
243
  it("set correct layer properties", () => {
204
244
  const layer = style.layers[0] as FillLayerSpecification;
205
245
  expect(layer.type).toBe(`fill`);
206
- expect(layer.paint["fill-color"]).toBe("rgba(255,255,255,0.4)");
207
- expect(layer.paint["fill-opacity"]).toBeUndefined();
246
+ expect(layer.paint?.["fill-color"]).toBe("rgba(255,255,255,0.4)");
247
+ expect(layer.paint?.["fill-opacity"]).toBe(1);
248
+ expect(layer.layout?.visibility).toBe("visible");
208
249
  });
209
250
  });
210
251
  });
211
252
  });
253
+
212
254
  describe("WFS", () => {
213
255
  beforeEach(async () => {
214
- (layerModel = MAP_CTX_LAYER_WFS_FIXTURE),
215
- (style = await createLayer(layerModel, 1));
256
+ layerModel = MAP_CTX_LAYER_WFS_FIXTURE;
257
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
216
258
  });
217
259
  it("create a vector layer", () => {
218
260
  expect(style).toBeTruthy();
@@ -222,7 +264,7 @@ describe("MapContextService", () => {
222
264
  expect(sourcesIds.length).toBe(1);
223
265
  const id = sourcesIds[0];
224
266
  const source = style.sources[id] as GeoJSONSourceSpecification;
225
- expect(id).toBe("985400327");
267
+ expect(id).toBe("123456");
226
268
  expect(source.data).toEqual(
227
269
  "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",
228
270
  );
@@ -231,35 +273,36 @@ describe("MapContextService", () => {
231
273
  expect(style.layers).toBeTruthy();
232
274
  expect(style.layers.length).toBe(3);
233
275
 
234
- let layer: LayerSpecification = style
235
- .layers[0] as FillLayerSpecification;
236
- expect(layer.id).toBe("985400327-fill");
237
- expect(layer.source).toBe("985400327");
238
- expect(layer.metadata.sourcePosition).toBe(1);
276
+ const sourceId = "123456";
277
+ const fillLayer = style.layers[0] as FillLayerSpecification;
278
+ const metadata = fillLayer.metadata as LayerMetadataSpecification;
239
279
 
240
- layer = style.layers[1] as LineLayerSpecification;
241
- expect(layer.id).toBe("985400327-line");
242
- expect(layer.source).toBe("985400327");
243
- expect(layer.metadata.sourcePosition).toBe(1);
280
+ expect(fillLayer.id).toBe(`${sourceId}-fill`);
281
+ expect(fillLayer.source).toBe(sourceId);
282
+ expect(metadata.layerId).toBeUndefined();
283
+ expect(metadata.layerHash).toBeTypeOf("string");
284
+ expect(fillLayer.paint?.["fill-opacity"]).toBe(0.5);
285
+ expect(fillLayer.layout?.visibility).toBe("visible");
244
286
 
245
- layer = style.layers[2] as CircleLayerSpecification;
246
- expect(layer.id).toBe("985400327-circle");
247
- expect(layer.source).toBe("985400327");
248
- expect(layer.metadata.sourcePosition).toBe(1);
287
+ const lineLayer = style.layers[1] as LineLayerSpecification;
288
+ expect(lineLayer.id).toBe(`${sourceId}-line`);
289
+ expect(lineLayer.source).toBe(sourceId);
290
+ expect(lineLayer.paint?.["line-opacity"]).toBe(0.5);
291
+ expect(lineLayer.layout?.visibility).toBe("visible");
292
+
293
+ const circleLayer = style.layers[2] as CircleLayerSpecification;
294
+ expect(circleLayer.id).toBe(`${sourceId}-circle`);
295
+ expect(circleLayer.source).toBe(sourceId);
296
+ expect(circleLayer.paint?.["circle-opacity"]).toBe(0.5);
297
+ expect(circleLayer.paint?.["circle-stroke-opacity"]).toBe(0.5);
298
+ expect(circleLayer.layout?.visibility).toBe("visible");
249
299
  });
250
300
  });
301
+
251
302
  describe("OGCAPI", () => {
252
303
  beforeEach(async () => {
253
- global.fetch = vi.fn(() =>
254
- Promise.resolve({
255
- ok: true,
256
- json: () =>
257
- Promise.resolve(FEATURE_COLLECTION_LINESTRING_FIXTURE_4326),
258
- }),
259
- );
260
-
261
- (layerModel = MAP_CTX_LAYER_OGCAPI_FIXTURE),
262
- (style = await createLayer(layerModel, 0));
304
+ layerModel = MAP_CTX_LAYER_OGCAPI_FIXTURE;
305
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
263
306
  });
264
307
  it("create a vector layer", () => {
265
308
  expect(style).toBeTruthy();
@@ -269,7 +312,7 @@ describe("MapContextService", () => {
269
312
  expect(sourcesIds.length).toBe(1);
270
313
  const id = sourcesIds[0];
271
314
  const source = style.sources[id] as GeoJSONSourceSpecification;
272
- expect(id).toBe("504003385");
315
+ expect(id).toBe("123456");
273
316
  expect(source.data).toEqual(
274
317
  "https://demo.ldproxy.net/zoomstack/collections/airports/items?f=json",
275
318
  );
@@ -277,10 +320,62 @@ describe("MapContextService", () => {
277
320
  it("create 3 layers", () => {
278
321
  expect(style.layers).toBeTruthy();
279
322
  expect(style.layers.length).toBe(3);
323
+
324
+ const sourceId = "123456";
280
325
  const layer = style.layers[0] as FillLayerSpecification;
281
- expect(layer.id).toBe("504003385-fill");
282
- expect(layer.source).toBe("504003385");
283
- expect(layer.metadata.sourcePosition).toBe(0);
326
+ const metadata = layer.metadata as LayerMetadataSpecification;
327
+
328
+ expect(layer.id).toBe(`${sourceId}-fill`);
329
+ expect(layer.source).toBe(sourceId);
330
+ expect(metadata.layerId).toBeUndefined();
331
+ expect(metadata.layerHash).toBeTypeOf("string");
332
+ expect(layer.paint?.["fill-opacity"]).toBe(1);
333
+ expect(layer.layout?.visibility).toBe("visible");
334
+ });
335
+ });
336
+
337
+ describe("XYZ", () => {
338
+ beforeEach(async () => {
339
+ layerModel = MAP_CTX_LAYER_XYZ_FIXTURE;
340
+ style = (await createLayer(layerModel)) as PartialStyleSpecification;
341
+ });
342
+ it("create a layer and source", () => {
343
+ const sourceId = "123456";
344
+
345
+ expect(style).toEqual({
346
+ layers: [
347
+ {
348
+ id: sourceId,
349
+ layout: {
350
+ visibility: "visible",
351
+ },
352
+ metadata: {
353
+ layerHash: "3863171382",
354
+ },
355
+ paint: {
356
+ "raster-opacity": 1,
357
+ },
358
+ source: sourceId,
359
+ type: "raster",
360
+ },
361
+ ],
362
+ sources: {
363
+ [sourceId]: {
364
+ tileSize: 256,
365
+ tiles: ["https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png"],
366
+ type: "raster",
367
+ },
368
+ },
369
+ });
370
+ });
371
+ });
372
+
373
+ describe("WMTS", () => {
374
+ beforeEach(async () => {
375
+ layerModel = MAP_CTX_LAYER_WMTS_FIXTURE;
376
+ });
377
+ it("does not support this layer type", async () => {
378
+ expect(await createLayer(layerModel)).toBe(null);
284
379
  });
285
380
  });
286
381
  });