@geospatial-sdk/maplibre 0.0.5-dev.41
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/LICENSE +28 -0
- package/README.md +11 -0
- package/dist/helpers/map.helpers.d.ts +21 -0
- package/dist/helpers/map.helpers.d.ts.map +1 -0
- package/dist/helpers/map.helpers.js +65 -0
- package/dist/helpers/style.helpers.d.ts +4 -0
- package/dist/helpers/style.helpers.d.ts.map +1 -0
- package/dist/helpers/style.helpers.js +54 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/map/apply-context-diff.d.ts +9 -0
- package/dist/map/apply-context-diff.d.ts.map +1 -0
- package/dist/map/apply-context-diff.js +71 -0
- package/dist/map/create-map.d.ts +17 -0
- package/dist/map/create-map.d.ts.map +1 -0
- package/dist/map/create-map.js +144 -0
- package/dist/map/index.d.ts +3 -0
- package/dist/map/index.d.ts.map +1 -0
- package/dist/map/index.js +2 -0
- package/dist/maplibre.models.d.ts +13 -0
- package/dist/maplibre.models.d.ts.map +1 -0
- package/dist/maplibre.models.js +1 -0
- package/lib/helpers/map.helpers.ts +101 -0
- package/lib/helpers/style.helpers.test.ts +160 -0
- package/lib/helpers/style.helpers.ts +68 -0
- package/lib/index.ts +2 -0
- package/lib/map/apply-context-diff.test.ts +152 -0
- package/lib/map/apply-context-diff.ts +89 -0
- package/lib/map/create-map.test.ts +287 -0
- package/lib/map/create-map.ts +173 -0
- package/lib/map/index.ts +2 -0
- package/lib/maplibre.models.ts +31 -0
- package/package.json +39 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
MAP_CTX_LAYER_GEOJSON_FIXTURE,
|
|
4
|
+
MAP_CTX_LAYER_GEOJSON_REMOTE_FIXTURE,
|
|
5
|
+
MAP_CTX_LAYER_OGCAPI_FIXTURE,
|
|
6
|
+
MAP_CTX_LAYER_WFS_FIXTURE,
|
|
7
|
+
MAP_CTX_LAYER_WMS_FIXTURE,
|
|
8
|
+
} from "@geospatial-sdk/core/fixtures/map-context.fixtures";
|
|
9
|
+
import { LayerGeojsonWithData, MapContextLayer } from "@geospatial-sdk/core";
|
|
10
|
+
import { createLayer } from "./create-map";
|
|
11
|
+
import {
|
|
12
|
+
FillLayerSpecification,
|
|
13
|
+
GeoJSONSourceSpecification,
|
|
14
|
+
RasterLayerSpecification,
|
|
15
|
+
} from "@maplibre/maplibre-gl-style-spec";
|
|
16
|
+
import {
|
|
17
|
+
FEATURE_COLLECTION_LINESTRING_FIXTURE_4326,
|
|
18
|
+
FEATURE_COLLECTION_POLYGON_FIXTURE_4326,
|
|
19
|
+
} from "@geospatial-sdk/core/fixtures/geojson.fixtures";
|
|
20
|
+
import { PartialStyleSpecification } from "../maplibre.models";
|
|
21
|
+
import {
|
|
22
|
+
CircleLayerSpecification,
|
|
23
|
+
LayerSpecification,
|
|
24
|
+
LineLayerSpecification,
|
|
25
|
+
RasterSourceSpecification,
|
|
26
|
+
} from "maplibre-gl";
|
|
27
|
+
|
|
28
|
+
describe("MapContextService", () => {
|
|
29
|
+
describe("#createLayer", () => {
|
|
30
|
+
let layerModel: MapContextLayer, style: PartialStyleSpecification;
|
|
31
|
+
|
|
32
|
+
describe("WMS", () => {
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
(layerModel = MAP_CTX_LAYER_WMS_FIXTURE),
|
|
35
|
+
(style = await createLayer(layerModel, 0));
|
|
36
|
+
});
|
|
37
|
+
it("create a tile layer", () => {
|
|
38
|
+
expect(style).toBeTruthy();
|
|
39
|
+
});
|
|
40
|
+
it("create a source", () => {
|
|
41
|
+
const sourcesIds = Object.keys(style.sources);
|
|
42
|
+
expect(sourcesIds.length).toBe(1);
|
|
43
|
+
const id = sourcesIds[0];
|
|
44
|
+
const source = style.sources[id] as RasterSourceSpecification;
|
|
45
|
+
expect(id).toBe("1046815418");
|
|
46
|
+
expect(source.tiles).toEqual([
|
|
47
|
+
"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
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
it("create a layer", () => {
|
|
51
|
+
expect(style.layers).toBeTruthy();
|
|
52
|
+
expect(style.layers.length).toBe(1);
|
|
53
|
+
|
|
54
|
+
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`);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe("GEOJSON", () => {
|
|
61
|
+
describe("with inline data", () => {
|
|
62
|
+
beforeEach(async () => {
|
|
63
|
+
layerModel = MAP_CTX_LAYER_GEOJSON_FIXTURE;
|
|
64
|
+
style = await createLayer(layerModel, 0);
|
|
65
|
+
Math.random = vi.fn(() => 0.027404);
|
|
66
|
+
});
|
|
67
|
+
it("create a VectorLayer", () => {
|
|
68
|
+
expect(style).toBeTruthy();
|
|
69
|
+
});
|
|
70
|
+
it("create a source", () => {
|
|
71
|
+
const sourcesIds = Object.keys(style.sources);
|
|
72
|
+
expect(sourcesIds.length).toBe(1);
|
|
73
|
+
expect(sourcesIds[0]).toBe("2792250259");
|
|
74
|
+
});
|
|
75
|
+
it("create 3 layers", () => {
|
|
76
|
+
expect(style.layers).toBeTruthy();
|
|
77
|
+
expect(style.layers.length).toBe(3);
|
|
78
|
+
|
|
79
|
+
let layer = style.layers[0] as RasterLayerSpecification;
|
|
80
|
+
expect(layer.id).toBe("2792250259-fill");
|
|
81
|
+
expect(layer.source).toBe("2792250259");
|
|
82
|
+
|
|
83
|
+
layer = style.layers[1] as RasterLayerSpecification;
|
|
84
|
+
expect(layer.id).toBe("2792250259-line");
|
|
85
|
+
expect(layer.source).toBe("2792250259");
|
|
86
|
+
|
|
87
|
+
layer = style.layers[2] as RasterLayerSpecification;
|
|
88
|
+
expect(layer.id).toBe("2792250259-circle");
|
|
89
|
+
expect(layer.source).toBe("2792250259");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("set correct source properties", () => {
|
|
93
|
+
const sourcesIds = Object.keys(style.sources);
|
|
94
|
+
const source = style.sources[
|
|
95
|
+
sourcesIds[0]
|
|
96
|
+
] as GeoJSONSourceSpecification;
|
|
97
|
+
expect(source.type).toBe("geojson");
|
|
98
|
+
expect(source.data).toBe((layerModel as LayerGeojsonWithData).data);
|
|
99
|
+
});
|
|
100
|
+
it("set correct layer properties", () => {
|
|
101
|
+
const layer = style.layers[0] as FillLayerSpecification;
|
|
102
|
+
expect(layer.type).toBe(`fill`);
|
|
103
|
+
expect(layer.paint["fill-color"]).toBe("rgba(255,255,255,0.4)");
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("with inline data as string", () => {
|
|
107
|
+
beforeEach(async () => {
|
|
108
|
+
layerModel = { ...MAP_CTX_LAYER_GEOJSON_FIXTURE };
|
|
109
|
+
layerModel.data = JSON.stringify(layerModel.data);
|
|
110
|
+
style = await createLayer(layerModel, 0);
|
|
111
|
+
});
|
|
112
|
+
it("create a VectorLayer", () => {
|
|
113
|
+
expect(style).toBeTruthy();
|
|
114
|
+
});
|
|
115
|
+
it("create a source", () => {
|
|
116
|
+
const sourcesIds = Object.keys(style.sources);
|
|
117
|
+
expect(sourcesIds.length).toBe(1);
|
|
118
|
+
});
|
|
119
|
+
it("create 3 layers", () => {
|
|
120
|
+
expect(style.layers).toBeTruthy();
|
|
121
|
+
expect(style.layers.length).toBe(3);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("set correct source properties", () => {
|
|
125
|
+
const sourcesIds = Object.keys(style.sources);
|
|
126
|
+
const source = style.sources[
|
|
127
|
+
sourcesIds[0]
|
|
128
|
+
] as GeoJSONSourceSpecification;
|
|
129
|
+
expect(source.type).toBe("geojson");
|
|
130
|
+
expect(source.data).toEqual(MAP_CTX_LAYER_GEOJSON_FIXTURE.data);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("set correct layer properties", () => {
|
|
134
|
+
const layer = style.layers[0] as FillLayerSpecification;
|
|
135
|
+
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();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe("with invalid inline data as string", () => {
|
|
141
|
+
beforeEach(async () => {
|
|
142
|
+
const spy = vi.spyOn(window.console, "warn");
|
|
143
|
+
spy.mockClear();
|
|
144
|
+
layerModel = {
|
|
145
|
+
...MAP_CTX_LAYER_GEOJSON_FIXTURE,
|
|
146
|
+
url: undefined,
|
|
147
|
+
data: "blargz",
|
|
148
|
+
} as LayerGeojsonWithData;
|
|
149
|
+
style = await createLayer(layerModel, 0);
|
|
150
|
+
});
|
|
151
|
+
it("create a VectorLayer", () => {
|
|
152
|
+
expect(style).toBeTruthy();
|
|
153
|
+
});
|
|
154
|
+
it("outputs error in the console", () => {
|
|
155
|
+
expect(window.console.warn).toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
it("create an empty VectorSource source", () => {
|
|
158
|
+
expect(style.sources).toEqual({
|
|
159
|
+
"3631250040": {
|
|
160
|
+
data: {
|
|
161
|
+
features: [],
|
|
162
|
+
type: "FeatureCollection",
|
|
163
|
+
},
|
|
164
|
+
type: "geojson",
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe("with remote file url", () => {
|
|
169
|
+
beforeEach(async () => {
|
|
170
|
+
layerModel = MAP_CTX_LAYER_GEOJSON_REMOTE_FIXTURE;
|
|
171
|
+
global.fetch = vi.fn(() =>
|
|
172
|
+
Promise.resolve({
|
|
173
|
+
ok: true,
|
|
174
|
+
json: () =>
|
|
175
|
+
Promise.resolve(FEATURE_COLLECTION_POLYGON_FIXTURE_4326),
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
style = await createLayer(layerModel, 0);
|
|
179
|
+
});
|
|
180
|
+
it("create a VectorLayer", () => {
|
|
181
|
+
expect(style).toBeTruthy();
|
|
182
|
+
});
|
|
183
|
+
it("create a source", () => {
|
|
184
|
+
const sourcesIds = Object.keys(style.sources);
|
|
185
|
+
expect(sourcesIds.length).toBe(1);
|
|
186
|
+
});
|
|
187
|
+
it("create 3 layers", () => {
|
|
188
|
+
expect(style.layers).toBeTruthy();
|
|
189
|
+
expect(style.layers.length).toBe(3);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("set correct source properties", () => {
|
|
193
|
+
const sourcesIds = Object.keys(style.sources);
|
|
194
|
+
const source = style.sources[
|
|
195
|
+
sourcesIds[0]
|
|
196
|
+
] as GeoJSONSourceSpecification;
|
|
197
|
+
expect(source.type).toBe("geojson");
|
|
198
|
+
expect(source.data).toEqual(
|
|
199
|
+
"https://my.host.com/data/regions.json",
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("set correct layer properties", () => {
|
|
204
|
+
const layer = style.layers[0] as FillLayerSpecification;
|
|
205
|
+
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();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe("WFS", () => {
|
|
213
|
+
beforeEach(async () => {
|
|
214
|
+
(layerModel = MAP_CTX_LAYER_WFS_FIXTURE),
|
|
215
|
+
(style = await createLayer(layerModel, 1));
|
|
216
|
+
});
|
|
217
|
+
it("create a vector layer", () => {
|
|
218
|
+
expect(style).toBeTruthy();
|
|
219
|
+
});
|
|
220
|
+
it("create a source", () => {
|
|
221
|
+
const sourcesIds = Object.keys(style.sources);
|
|
222
|
+
expect(sourcesIds.length).toBe(1);
|
|
223
|
+
const id = sourcesIds[0];
|
|
224
|
+
const source = style.sources[id] as GeoJSONSourceSpecification;
|
|
225
|
+
expect(id).toBe("985400327");
|
|
226
|
+
expect(source.data).toEqual(
|
|
227
|
+
"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
|
+
);
|
|
229
|
+
});
|
|
230
|
+
it("create 3 layers", () => {
|
|
231
|
+
expect(style.layers).toBeTruthy();
|
|
232
|
+
expect(style.layers.length).toBe(3);
|
|
233
|
+
|
|
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);
|
|
239
|
+
|
|
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);
|
|
244
|
+
|
|
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);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
describe("OGCAPI", () => {
|
|
252
|
+
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));
|
|
263
|
+
});
|
|
264
|
+
it("create a vector layer", () => {
|
|
265
|
+
expect(style).toBeTruthy();
|
|
266
|
+
});
|
|
267
|
+
it("create a source", () => {
|
|
268
|
+
const sourcesIds = Object.keys(style.sources);
|
|
269
|
+
expect(sourcesIds.length).toBe(1);
|
|
270
|
+
const id = sourcesIds[0];
|
|
271
|
+
const source = style.sources[id] as GeoJSONSourceSpecification;
|
|
272
|
+
expect(id).toBe("504003385");
|
|
273
|
+
expect(source.data).toEqual(
|
|
274
|
+
"https://demo.ldproxy.net/zoomstack/collections/airports/items?f=json",
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
it("create 3 layers", () => {
|
|
278
|
+
expect(style.layers).toBeTruthy();
|
|
279
|
+
expect(style.layers.length).toBe(3);
|
|
280
|
+
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);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MapContext,
|
|
3
|
+
MapContextLayer,
|
|
4
|
+
removeSearchParams,
|
|
5
|
+
ViewByZoomAndCenter,
|
|
6
|
+
} from "@geospatial-sdk/core";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
LayerSpecification,
|
|
10
|
+
Map,
|
|
11
|
+
MapOptions,
|
|
12
|
+
StyleSpecification,
|
|
13
|
+
} from "maplibre-gl";
|
|
14
|
+
import { FeatureCollection, Geometry } from "geojson";
|
|
15
|
+
import {
|
|
16
|
+
OgcApiEndpoint,
|
|
17
|
+
WfsEndpoint,
|
|
18
|
+
WmsEndpoint,
|
|
19
|
+
} from "@camptocamp/ogc-client";
|
|
20
|
+
import {
|
|
21
|
+
createDatasetFromGeoJsonLayer,
|
|
22
|
+
generateLayerId,
|
|
23
|
+
} from "../helpers/map.helpers";
|
|
24
|
+
import { Dataset, PartialStyleSpecification } from "../maplibre.models";
|
|
25
|
+
|
|
26
|
+
const featureCollection: FeatureCollection<Geometry | null> = {
|
|
27
|
+
type: "FeatureCollection",
|
|
28
|
+
features: [],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export async function createLayer(
|
|
32
|
+
layerModel: MapContextLayer,
|
|
33
|
+
sourcePosition: number,
|
|
34
|
+
): Promise<PartialStyleSpecification> {
|
|
35
|
+
const { type } = layerModel;
|
|
36
|
+
|
|
37
|
+
switch (type) {
|
|
38
|
+
case "wms": {
|
|
39
|
+
const layerId = generateLayerId(layerModel);
|
|
40
|
+
const sourceId = layerId;
|
|
41
|
+
|
|
42
|
+
const endpoint = await new WmsEndpoint(layerModel.url).isReady();
|
|
43
|
+
let url = endpoint.getMapUrl([layerModel.name], {
|
|
44
|
+
widthPx: 256,
|
|
45
|
+
heightPx: 256,
|
|
46
|
+
extent: [0, 0, 0, 0], // will be replaced by maplibre-gl
|
|
47
|
+
outputFormat: "image/png",
|
|
48
|
+
crs: "EPSG:3857",
|
|
49
|
+
});
|
|
50
|
+
url = removeSearchParams(url, ["bbox"]);
|
|
51
|
+
url = `${url.toString()}&BBOX={bbox-epsg-3857}`;
|
|
52
|
+
|
|
53
|
+
const dataset: Dataset = {
|
|
54
|
+
sources: {
|
|
55
|
+
[sourceId]: {
|
|
56
|
+
type: "raster",
|
|
57
|
+
tiles: [url],
|
|
58
|
+
tileSize: 256,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
layers: [
|
|
62
|
+
{
|
|
63
|
+
id: layerId,
|
|
64
|
+
type: "raster",
|
|
65
|
+
source: sourceId,
|
|
66
|
+
paint: {},
|
|
67
|
+
metadata: {
|
|
68
|
+
sourcePosition,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
return dataset;
|
|
74
|
+
}
|
|
75
|
+
case "wfs": {
|
|
76
|
+
const entryPoint = await new WfsEndpoint(layerModel.url).isReady();
|
|
77
|
+
const url = entryPoint.getFeatureUrl(layerModel.featureType, {
|
|
78
|
+
asJson: true,
|
|
79
|
+
outputCrs: "EPSG:4326",
|
|
80
|
+
});
|
|
81
|
+
return createDatasetFromGeoJsonLayer(layerModel, url, sourcePosition);
|
|
82
|
+
}
|
|
83
|
+
case "geojson": {
|
|
84
|
+
let geojson;
|
|
85
|
+
if (layerModel.url !== undefined) {
|
|
86
|
+
geojson = layerModel.url;
|
|
87
|
+
} else {
|
|
88
|
+
const data = layerModel.data;
|
|
89
|
+
if (typeof data === "string") {
|
|
90
|
+
try {
|
|
91
|
+
geojson = JSON.parse(data) as FeatureCollection;
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.warn("A layer could not be created", layerModel, e);
|
|
94
|
+
geojson = featureCollection;
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
geojson = data;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return createDatasetFromGeoJsonLayer(layerModel, geojson, sourcePosition);
|
|
101
|
+
}
|
|
102
|
+
case "ogcapi": {
|
|
103
|
+
const ogcEndpoint = new OgcApiEndpoint(layerModel.url);
|
|
104
|
+
let layerUrl: string;
|
|
105
|
+
if (layerModel.useTiles) {
|
|
106
|
+
console.warn("[Warning] OGC API - Tiles not yet implemented.");
|
|
107
|
+
} else {
|
|
108
|
+
layerUrl = await ogcEndpoint.getCollectionItemsUrl(
|
|
109
|
+
layerModel.collection,
|
|
110
|
+
{ ...layerModel.options, asJson: true },
|
|
111
|
+
);
|
|
112
|
+
return createDatasetFromGeoJsonLayer(
|
|
113
|
+
layerModel,
|
|
114
|
+
layerUrl,
|
|
115
|
+
sourcePosition,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "maplibre-style": {
|
|
121
|
+
console.warn("[Warning] Maplibre style - Not yet fully implemented.");
|
|
122
|
+
const style = await fetch(layerModel.styleUrl).then((res) => res.json());
|
|
123
|
+
style.layers?.forEach(
|
|
124
|
+
(layer: LayerSpecification) => (layer.metadata = { sourcePosition }),
|
|
125
|
+
);
|
|
126
|
+
return style;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {} as StyleSpecification;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Create an Maplibre map from a context; optionally specify a target (root element) for the map
|
|
134
|
+
* @param context
|
|
135
|
+
* @param target
|
|
136
|
+
*/
|
|
137
|
+
export async function createMapFromContext(
|
|
138
|
+
context: MapContext,
|
|
139
|
+
mapOptions: MapOptions,
|
|
140
|
+
): Promise<Map> {
|
|
141
|
+
const map = new Map(mapOptions);
|
|
142
|
+
return await resetMapFromContext(map, context);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Resets a Maplibre map from a context; existing content will be cleared
|
|
147
|
+
* @param map
|
|
148
|
+
* @param context
|
|
149
|
+
*/
|
|
150
|
+
export async function resetMapFromContext(
|
|
151
|
+
map: Map,
|
|
152
|
+
context: MapContext,
|
|
153
|
+
): Promise<Map> {
|
|
154
|
+
map.setZoom((context.view as ViewByZoomAndCenter).zoom);
|
|
155
|
+
map.setCenter((context.view as ViewByZoomAndCenter).center);
|
|
156
|
+
|
|
157
|
+
for (let i = 0; i < context.layers.length; i++) {
|
|
158
|
+
const layerModel = context.layers[i];
|
|
159
|
+
const partialMLStyle = await createLayer(layerModel, i);
|
|
160
|
+
|
|
161
|
+
if (partialMLStyle.glyphs) {
|
|
162
|
+
map.setGlyphs(partialMLStyle.glyphs);
|
|
163
|
+
}
|
|
164
|
+
if (partialMLStyle.sprite) {
|
|
165
|
+
map.setSprite(partialMLStyle.sprite as string);
|
|
166
|
+
}
|
|
167
|
+
Object.keys(partialMLStyle.sources).forEach((sourceId) =>
|
|
168
|
+
map.addSource(sourceId, partialMLStyle.sources[sourceId]),
|
|
169
|
+
);
|
|
170
|
+
partialMLStyle.layers.map((layer) => map.addLayer(layer));
|
|
171
|
+
}
|
|
172
|
+
return map;
|
|
173
|
+
}
|
package/lib/map/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BackgroundLayerSpecification,
|
|
3
|
+
LayerSpecification,
|
|
4
|
+
StyleSpecification,
|
|
5
|
+
} from "maplibre-gl";
|
|
6
|
+
import {
|
|
7
|
+
MapContextLayerGeojson,
|
|
8
|
+
MapContextLayerOgcApi,
|
|
9
|
+
MapContextLayerWfs,
|
|
10
|
+
} from "@geospatial-sdk/core";
|
|
11
|
+
|
|
12
|
+
export type LayerSpecificationWithSource = Exclude<
|
|
13
|
+
LayerSpecification,
|
|
14
|
+
BackgroundLayerSpecification
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
export interface LayerMetadataSpecification {
|
|
18
|
+
sourcePosition: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type LayerContextWithStyle =
|
|
22
|
+
| MapContextLayerWfs
|
|
23
|
+
| MapContextLayerOgcApi
|
|
24
|
+
| MapContextLayerGeojson;
|
|
25
|
+
|
|
26
|
+
export type Dataset = Pick<StyleSpecification, "sources" | "layers">;
|
|
27
|
+
|
|
28
|
+
export type PartialStyleSpecification = Dataset & {
|
|
29
|
+
glyphs?: StyleSpecification["glyphs"];
|
|
30
|
+
sprite?: StyleSpecification["sprite"];
|
|
31
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geospatial-sdk/maplibre",
|
|
3
|
+
"version": "0.0.5-dev.41+dba0603",
|
|
4
|
+
"description": "Maplibre-related utilities",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"maplibre",
|
|
7
|
+
"map"
|
|
8
|
+
],
|
|
9
|
+
"author": "Florent Gravin <florent.gravin@camptocamp.com>",
|
|
10
|
+
"homepage": "",
|
|
11
|
+
"license": "BSD-3-Clause",
|
|
12
|
+
"main": "dist/index.js",
|
|
13
|
+
"typings": "dist/index.d.ts",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"directories": {
|
|
19
|
+
"lib": "lib"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"lib",
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "vitest",
|
|
27
|
+
"build": "tsc"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"maplibre-gl": "^5.7.3"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"maplibre-gl": "^5.7.3"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@geospatial-sdk/core": "^0.0.5-dev.41+dba0603"
|
|
37
|
+
},
|
|
38
|
+
"gitHead": "dba060374167251ca486946c95e8a885c121ccd5"
|
|
39
|
+
}
|