@geospatial-sdk/openlayers 0.0.5-dev.47 → 0.0.5-dev.48

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 +1 @@
1
- {"version":3,"file":"apply-context-diff.d.ts","sourceRoot":"","sources":["../../lib/map/apply-context-diff.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,WAAW,CAAC;AAC5B,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,CA2Fd"}
1
+ {"version":3,"file":"apply-context-diff.d.ts","sourceRoot":"","sources":["../../lib/map/apply-context-diff.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,WAAW,CAAC;AAC5B,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,CA6Fd"}
@@ -1,4 +1,4 @@
1
- import { createLayer, createView } from "./create-map.js";
1
+ import { createLayer, createView, updateLayerInMap } from "./create-map.js";
2
2
  import { fromLonLat, transformExtent } from "ol/proj.js";
3
3
  import GeoJSON from "ol/format/GeoJSON.js";
4
4
  const GEOJSON = new GeoJSON();
@@ -38,12 +38,9 @@ export async function applyContextDiffToMap(map, contextDiff) {
38
38
  }
39
39
  map.setLayers([...layersArray]);
40
40
  }
41
- // recreate changed layers
41
+ // update or recreate changed layers
42
42
  for (const layerChanged of contextDiff.layersChanged) {
43
- layers.item(layerChanged.position).dispose();
44
- createLayer(layerChanged.layer).then((layer) => {
45
- layers.setAt(layerChanged.position, layer);
46
- });
43
+ updateLayerInMap(map, layerChanged.layer, layerChanged.position, layerChanged.previousLayer);
47
44
  }
48
45
  if (typeof contextDiff.viewChanges !== "undefined") {
49
46
  const { viewChanges } = contextDiff;
@@ -3,6 +3,7 @@ import Map from "ol/Map.js";
3
3
  import View from "ol/View.js";
4
4
  import Layer from "ol/layer/Layer.js";
5
5
  export declare function createLayer(layerModel: MapContextLayer): Promise<Layer>;
6
+ export declare function updateLayerInMap(map: Map, layerModel: MapContextLayer, layerPosition: number, previousLayer: MapContextLayer): void;
6
7
  export declare function createView(viewModel: MapContextView | null, map: Map): View;
7
8
  /**
8
9
  * Create an OpenLayers map from a context; optionally specify a target (root element) for the map
@@ -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,EAEf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,GAAG,MAAM,WAAW,CAAC;AAC5B,OAAO,IAAI,MAAM,YAAY,CAAC;AAC9B,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAkCtC,wBAAsB,WAAW,CAAC,UAAU,EAAE,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,CA8N7E;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAkC3E;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"}
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,WAAW,CAAC;AAC5B,OAAO,IAAI,MAAM,YAAY,CAAC;AAC9B,OAAO,KAAK,MAAM,mBAAmB,CAAC;AA6CtC,wBAAsB,WAAW,CAAC,UAAU,EAAE,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,CAyN7E;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,eAAe,EAC3B,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,eAAe,QAgB/B;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAkC3E;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"}
@@ -19,8 +19,18 @@ import { OgcApiEndpoint, WfsEndpoint, WmtsEndpoint, } from "@camptocamp/ogc-clie
19
19
  import { MapboxVectorLayer } from "ol-mapbox-style";
20
20
  import { handleEndpointError, tileLoadErrorCatchFunction, } from "./handle-errors.js";
21
21
  import VectorTile from "ol/source/VectorTile.js";
22
+ import { canDoIncrementalUpdate } from "./layer-update.js";
22
23
  const GEOJSON = new GeoJSON();
23
24
  const WFS_MAX_FEATURES = 10000;
25
+ function updateLayerProperties(layerModel, olLayer) {
26
+ typeof layerModel.visibility !== "undefined" &&
27
+ olLayer.setVisible(layerModel.visibility);
28
+ typeof layerModel.opacity !== "undefined" &&
29
+ olLayer.setOpacity(layerModel.opacity);
30
+ typeof layerModel.attributions !== "undefined" &&
31
+ olLayer.getSource()?.setAttributions(layerModel.attributions);
32
+ olLayer.set("label", layerModel.label);
33
+ }
24
34
  export async function createLayer(layerModel) {
25
35
  const { type } = layerModel;
26
36
  let layer;
@@ -216,15 +226,23 @@ export async function createLayer(layerModel) {
216
226
  if (!layer) {
217
227
  throw new Error(`Layer could not be created for type: ${layerModel.type}`);
218
228
  }
219
- typeof layerModel.visibility !== "undefined" &&
220
- layer.setVisible(layerModel.visibility);
221
- typeof layerModel.opacity !== "undefined" &&
222
- layer.setOpacity(layerModel.opacity);
223
- typeof layerModel.attributions !== "undefined" &&
224
- layer.getSource()?.setAttributions(layerModel.attributions);
225
- layer.set("label", layerModel.label);
229
+ updateLayerProperties(layerModel, layer);
226
230
  return layer;
227
231
  }
232
+ export function updateLayerInMap(map, layerModel, layerPosition, previousLayer) {
233
+ const layers = map.getLayers();
234
+ const updatedLayer = layers.item(layerPosition);
235
+ // if an incremental update is possible, do it to avoid costly layer recreation
236
+ if (canDoIncrementalUpdate(previousLayer, layerModel)) {
237
+ updateLayerProperties(layerModel, updatedLayer);
238
+ return;
239
+ }
240
+ // dispose and recreate layer
241
+ updatedLayer.dispose();
242
+ createLayer(layerModel).then((layer) => {
243
+ layers.setAt(layerPosition, layer);
244
+ });
245
+ }
228
246
  export function createView(viewModel, map) {
229
247
  if (viewModel === null) {
230
248
  return new View({
@@ -0,0 +1,13 @@
1
+ import { MapContextLayer } from "@geospatial-sdk/core";
2
+ /**
3
+ * Incremental update is possible only if certain properties are changed: opacity,
4
+ * visibility, zIndex, etc.
5
+ *
6
+ * Note: we assume that both layers are different versions of the same layer (this
7
+ * will not be checked again)
8
+ * @param oldLayer
9
+ * @param newLayer
10
+ * @return Returns `true` if the only properties changed are the updatable ones
11
+ */
12
+ export declare function canDoIncrementalUpdate(oldLayer: MapContextLayer, newLayer: MapContextLayer): boolean;
13
+ //# sourceMappingURL=layer-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-update.d.ts","sourceRoot":"","sources":["../../lib/map/layer-update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAahE;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAIT"}
@@ -0,0 +1,25 @@
1
+ import { getHash } from "@geospatial-sdk/core";
2
+ const UPDATABLE_PROPERTIES = [
3
+ "opacity",
4
+ "visibility",
5
+ "label",
6
+ "attributions",
7
+ "extras",
8
+ "version",
9
+ // TODO (when available) "zIndex"
10
+ ];
11
+ /**
12
+ * Incremental update is possible only if certain properties are changed: opacity,
13
+ * visibility, zIndex, etc.
14
+ *
15
+ * Note: we assume that both layers are different versions of the same layer (this
16
+ * will not be checked again)
17
+ * @param oldLayer
18
+ * @param newLayer
19
+ * @return Returns `true` if the only properties changed are the updatable ones
20
+ */
21
+ export function canDoIncrementalUpdate(oldLayer, newLayer) {
22
+ const oldHash = getHash(oldLayer, UPDATABLE_PROPERTIES);
23
+ const newHash = getHash(newLayer, UPDATABLE_PROPERTIES);
24
+ return oldHash === newHash;
25
+ }
@@ -127,6 +127,7 @@ describe("applyContextDiffToMap", () => {
127
127
  ...SAMPLE_LAYER2,
128
128
  url: "http://changed/",
129
129
  } as MapContextLayer,
130
+ previousLayer: SAMPLE_LAYER2,
130
131
  position: 0,
131
132
  },
132
133
  {
@@ -137,6 +138,7 @@ describe("applyContextDiffToMap", () => {
137
138
  changed: true,
138
139
  },
139
140
  } as MapContextLayer,
141
+ previousLayer: SAMPLE_LAYER1,
140
142
  position: 1,
141
143
  },
142
144
  ],
@@ -151,6 +153,38 @@ describe("applyContextDiffToMap", () => {
151
153
  assertEqualsToModel(layersArray[0], diff.layersChanged[0].layer);
152
154
  assertEqualsToModel(layersArray[1], diff.layersChanged[1].layer);
153
155
  });
156
+
157
+ describe("layers changed (updatable properties only)", () => {
158
+ let prevOlLayer: BaseLayer;
159
+ let newOlLayer: BaseLayer;
160
+ beforeEach(() => {
161
+ diff = {
162
+ layersAdded: [],
163
+ layersChanged: [
164
+ {
165
+ layer: {
166
+ ...SAMPLE_LAYER1,
167
+ attributions: "new attributions!",
168
+ } as MapContextLayer,
169
+ previousLayer: SAMPLE_LAYER1,
170
+ position: 1,
171
+ },
172
+ ],
173
+ layersRemoved: [],
174
+ layersReordered: [],
175
+ };
176
+ prevOlLayer = map.getLayers().item(1);
177
+ applyContextDiffToMap(map, diff);
178
+ newOlLayer = map.getLayers().item(1);
179
+ });
180
+ it("modifies the layer without recreating it", () => {
181
+ expect(prevOlLayer).toBe(newOlLayer);
182
+ const newAttributions = (newOlLayer as any)
183
+ .getSource()
184
+ ?.getAttributions();
185
+ expect(newAttributions()).toEqual(["new attributions!"]);
186
+ });
187
+ });
154
188
  });
155
189
 
156
190
  describe("reordering", () => {
@@ -319,6 +353,7 @@ describe("applyContextDiffToMap", () => {
319
353
  layersChanged: [
320
354
  {
321
355
  layer: changedLayer,
356
+ previousLayer: SAMPLE_LAYER3,
322
357
  position: 1,
323
358
  },
324
359
  ],
@@ -1,6 +1,6 @@
1
1
  import Map from "ol/Map.js";
2
2
  import { MapContextDiff } from "@geospatial-sdk/core";
3
- import { createLayer, createView } from "./create-map.js";
3
+ import { createLayer, createView, updateLayerInMap } from "./create-map.js";
4
4
  import { fromLonLat, transformExtent } from "ol/proj.js";
5
5
  import GeoJSON from "ol/format/GeoJSON.js";
6
6
  import SimpleGeometry from "ol/geom/SimpleGeometry.js";
@@ -58,12 +58,14 @@ export async function applyContextDiffToMap(
58
58
  map.setLayers([...layersArray]);
59
59
  }
60
60
 
61
- // recreate changed layers
61
+ // update or recreate changed layers
62
62
  for (const layerChanged of contextDiff.layersChanged) {
63
- layers.item(layerChanged.position).dispose();
64
- createLayer(layerChanged.layer).then((layer) => {
65
- layers.setAt(layerChanged.position, layer);
66
- });
63
+ updateLayerInMap(
64
+ map,
65
+ layerChanged.layer,
66
+ layerChanged.position,
67
+ layerChanged.previousLayer,
68
+ );
67
69
  }
68
70
 
69
71
  if (typeof contextDiff.viewChanges !== "undefined") {
@@ -36,10 +36,21 @@ import {
36
36
  tileLoadErrorCatchFunction,
37
37
  } from "./handle-errors.js";
38
38
  import VectorTile from "ol/source/VectorTile.js";
39
+ import { canDoIncrementalUpdate } from "./layer-update.js";
39
40
 
40
41
  const GEOJSON = new GeoJSON();
41
42
  const WFS_MAX_FEATURES = 10000;
42
43
 
44
+ function updateLayerProperties(layerModel: MapContextLayer, olLayer: Layer) {
45
+ typeof layerModel.visibility !== "undefined" &&
46
+ olLayer.setVisible(layerModel.visibility);
47
+ typeof layerModel.opacity !== "undefined" &&
48
+ olLayer.setOpacity(layerModel.opacity);
49
+ typeof layerModel.attributions !== "undefined" &&
50
+ olLayer.getSource()?.setAttributions(layerModel.attributions);
51
+ olLayer.set("label", layerModel.label);
52
+ }
53
+
43
54
  export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
44
55
  const { type } = layerModel;
45
56
  let layer: Layer | undefined;
@@ -253,17 +264,34 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
253
264
  if (!layer) {
254
265
  throw new Error(`Layer could not be created for type: ${layerModel.type}`);
255
266
  }
256
- typeof layerModel.visibility !== "undefined" &&
257
- layer.setVisible(layerModel.visibility);
258
- typeof layerModel.opacity !== "undefined" &&
259
- layer.setOpacity(layerModel.opacity);
260
- typeof layerModel.attributions !== "undefined" &&
261
- layer.getSource()?.setAttributions(layerModel.attributions);
262
- layer.set("label", layerModel.label);
267
+
268
+ updateLayerProperties(layerModel, layer);
263
269
 
264
270
  return layer;
265
271
  }
266
272
 
273
+ export function updateLayerInMap(
274
+ map: Map,
275
+ layerModel: MapContextLayer,
276
+ layerPosition: number,
277
+ previousLayer: MapContextLayer,
278
+ ) {
279
+ const layers = map.getLayers();
280
+ const updatedLayer = layers.item(layerPosition) as Layer;
281
+
282
+ // if an incremental update is possible, do it to avoid costly layer recreation
283
+ if (canDoIncrementalUpdate(previousLayer, layerModel)) {
284
+ updateLayerProperties(layerModel, updatedLayer);
285
+ return;
286
+ }
287
+
288
+ // dispose and recreate layer
289
+ updatedLayer.dispose();
290
+ createLayer(layerModel).then((layer) => {
291
+ layers.setAt(layerPosition, layer);
292
+ });
293
+ }
294
+
267
295
  export function createView(viewModel: MapContextView | null, map: Map): View {
268
296
  if (viewModel === null) {
269
297
  return new View({
@@ -0,0 +1,45 @@
1
+ import { canDoIncrementalUpdate } from "./layer-update.js";
2
+ import { MapContextLayer } from "@geospatial-sdk/core";
3
+
4
+ describe("Layer update utils", () => {
5
+ describe("canDoIncrementalUpdate", () => {
6
+ it("returns true if only updatable properties are changed", () => {
7
+ const oldLayer = {
8
+ name: "layer1",
9
+ type: "wms",
10
+ url: "https://example.com/wms",
11
+ opacity: 0.5,
12
+ visibility: true,
13
+ label: "Layer 1",
14
+ } as MapContextLayer;
15
+ const newLayer = {
16
+ name: "layer1",
17
+ type: "wms",
18
+ url: "https://example.com/wms",
19
+ opacity: 0.8,
20
+ label: "Layer 1 Updated",
21
+ extras: { hello: "world" },
22
+ } as MapContextLayer;
23
+ expect(canDoIncrementalUpdate(oldLayer, newLayer)).toBe(true);
24
+ });
25
+ it("returns false if non-updatable properties are changed", () => {
26
+ const oldLayer = {
27
+ name: "layer1",
28
+ type: "wms",
29
+ url: "https://example.com/wms",
30
+ opacity: 0.5,
31
+ visibility: true,
32
+ label: "Layer 1",
33
+ } as MapContextLayer;
34
+ const newLayer = {
35
+ name: "layer1",
36
+ type: "wms",
37
+ url: "https://example.com/wms/CHANGED",
38
+ opacity: 0.5,
39
+ visibility: true,
40
+ label: "Layer 1",
41
+ } as MapContextLayer;
42
+ expect(canDoIncrementalUpdate(oldLayer, newLayer)).toBe(false);
43
+ });
44
+ });
45
+ });
@@ -0,0 +1,31 @@
1
+ import { getHash, MapContextLayer } from "@geospatial-sdk/core";
2
+ import { MapContextBaseLayer } from "@geospatial-sdk/core/lib/model/map-context.js";
3
+
4
+ const UPDATABLE_PROPERTIES: (keyof MapContextBaseLayer)[] = [
5
+ "opacity",
6
+ "visibility",
7
+ "label",
8
+ "attributions",
9
+ "extras",
10
+ "version",
11
+ // TODO (when available) "zIndex"
12
+ ];
13
+
14
+ /**
15
+ * Incremental update is possible only if certain properties are changed: opacity,
16
+ * visibility, zIndex, etc.
17
+ *
18
+ * Note: we assume that both layers are different versions of the same layer (this
19
+ * will not be checked again)
20
+ * @param oldLayer
21
+ * @param newLayer
22
+ * @return Returns `true` if the only properties changed are the updatable ones
23
+ */
24
+ export function canDoIncrementalUpdate(
25
+ oldLayer: MapContextLayer,
26
+ newLayer: MapContextLayer,
27
+ ): boolean {
28
+ const oldHash = getHash(oldLayer, UPDATABLE_PROPERTIES);
29
+ const newHash = getHash(newLayer, UPDATABLE_PROPERTIES);
30
+ return oldHash === newHash;
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geospatial-sdk/openlayers",
3
- "version": "0.0.5-dev.47+37669e8",
3
+ "version": "0.0.5-dev.48+a6a661d",
4
4
  "description": "OpenLayers-related utilities",
5
5
  "keywords": [
6
6
  "ol",
@@ -37,10 +37,10 @@
37
37
  "ol": ">6.x"
38
38
  },
39
39
  "dependencies": {
40
- "@geospatial-sdk/core": "^0.0.5-dev.47+37669e8",
40
+ "@geospatial-sdk/core": "^0.0.5-dev.48+a6a661d",
41
41
  "chroma-js": "^2.4.2",
42
42
  "lodash.throttle": "^4.1.1",
43
43
  "ol-mapbox-style": "12.4.0"
44
44
  },
45
- "gitHead": "37669e815765d751c4795a67e671ae19e3bf5a92"
45
+ "gitHead": "a6a661d277224d3e0acef7e2df817a3c5b7360e1"
46
46
  }