@geospatial-sdk/openlayers 0.0.5-dev.47 → 0.0.5-dev.49
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 +3 -6
- package/dist/map/create-map.d.ts +1 -0
- package/dist/map/create-map.d.ts.map +1 -1
- package/dist/map/create-map.js +16 -7
- package/dist/map/layer-update.d.ts +22 -0
- package/dist/map/layer-update.d.ts.map +1 -0
- package/dist/map/layer-update.js +59 -0
- package/lib/map/apply-context-diff.test.ts +35 -0
- package/lib/map/apply-context-diff.ts +8 -6
- package/lib/map/create-map.ts +28 -7
- package/lib/map/layer-update.test.ts +115 -0
- package/lib/map/layer-update.ts +73 -0
- 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,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,
|
|
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
|
-
|
|
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;
|
package/dist/map/create-map.d.ts
CHANGED
|
@@ -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, previousLayerModel: 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;
|
|
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;AAsCtC,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,kBAAkB,EAAE,eAAe,QAgBpC;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"}
|
package/dist/map/create-map.js
CHANGED
|
@@ -19,6 +19,7 @@ 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, updateLayerProperties, } from "./layer-update.js";
|
|
22
23
|
const GEOJSON = new GeoJSON();
|
|
23
24
|
const WFS_MAX_FEATURES = 10000;
|
|
24
25
|
export async function createLayer(layerModel) {
|
|
@@ -216,15 +217,23 @@ export async function createLayer(layerModel) {
|
|
|
216
217
|
if (!layer) {
|
|
217
218
|
throw new Error(`Layer could not be created for type: ${layerModel.type}`);
|
|
218
219
|
}
|
|
219
|
-
|
|
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);
|
|
220
|
+
updateLayerProperties(layerModel, layer);
|
|
226
221
|
return layer;
|
|
227
222
|
}
|
|
223
|
+
export function updateLayerInMap(map, layerModel, layerPosition, previousLayerModel) {
|
|
224
|
+
const layers = map.getLayers();
|
|
225
|
+
const updatedLayer = layers.item(layerPosition);
|
|
226
|
+
// if an incremental update is possible, do it to avoid costly layer recreation
|
|
227
|
+
if (canDoIncrementalUpdate(previousLayerModel, layerModel)) {
|
|
228
|
+
updateLayerProperties(layerModel, updatedLayer, previousLayerModel);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
// dispose and recreate layer
|
|
232
|
+
updatedLayer.dispose();
|
|
233
|
+
createLayer(layerModel).then((layer) => {
|
|
234
|
+
layers.setAt(layerPosition, layer);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
228
237
|
export function createView(viewModel, map) {
|
|
229
238
|
if (viewModel === null) {
|
|
230
239
|
return new View({
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MapContextLayer } from "@geospatial-sdk/core";
|
|
2
|
+
import Layer from "ol/layer/Layer.js";
|
|
3
|
+
/**
|
|
4
|
+
* Incremental update is possible only if certain properties are changed: opacity,
|
|
5
|
+
* visibility, zIndex, etc.
|
|
6
|
+
*
|
|
7
|
+
* Note: we assume that both layers are different versions of the same layer (this
|
|
8
|
+
* will not be checked again)
|
|
9
|
+
* @param oldLayer
|
|
10
|
+
* @param newLayer
|
|
11
|
+
* @return Returns `true` if the only properties changed are the updatable ones
|
|
12
|
+
*/
|
|
13
|
+
export declare function canDoIncrementalUpdate(oldLayer: MapContextLayer, newLayer: MapContextLayer): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Will apply generic properties to the layer; if a previous layer model is provided,
|
|
16
|
+
* only changed properties will be updated (to avoid costly change events in OpenLayers)
|
|
17
|
+
* @param layerModel
|
|
18
|
+
* @param olLayer
|
|
19
|
+
* @param previousLayerModel
|
|
20
|
+
*/
|
|
21
|
+
export declare function updateLayerProperties(layerModel: MapContextLayer, olLayer: Layer, previousLayerModel?: MapContextLayer): void;
|
|
22
|
+
//# 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;AAEhE,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAYtC;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAIT;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,KAAK,EACd,kBAAkB,CAAC,EAAE,eAAe,QA6BrC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Will apply generic properties to the layer; if a previous layer model is provided,
|
|
28
|
+
* only changed properties will be updated (to avoid costly change events in OpenLayers)
|
|
29
|
+
* @param layerModel
|
|
30
|
+
* @param olLayer
|
|
31
|
+
* @param previousLayerModel
|
|
32
|
+
*/
|
|
33
|
+
export function updateLayerProperties(layerModel, olLayer, previousLayerModel) {
|
|
34
|
+
function shouldApplyProperty(prop) {
|
|
35
|
+
// if the new layer model does not define that property, skip it
|
|
36
|
+
// (setting or resetting it to a default value would be counter-intuitive)
|
|
37
|
+
if (!(prop in layerModel) || typeof layerModel[prop] === "undefined")
|
|
38
|
+
return false;
|
|
39
|
+
// if a previous model is provided and the value did not change in the new layer model, skip it
|
|
40
|
+
if (previousLayerModel && layerModel[prop] === previousLayerModel[prop]) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
// any other case: apply the property
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (shouldApplyProperty("visibility")) {
|
|
47
|
+
olLayer.setVisible(layerModel.visibility);
|
|
48
|
+
}
|
|
49
|
+
if (shouldApplyProperty("opacity")) {
|
|
50
|
+
olLayer.setOpacity(layerModel.opacity);
|
|
51
|
+
}
|
|
52
|
+
if (shouldApplyProperty("attributions")) {
|
|
53
|
+
olLayer.getSource()?.setAttributions(layerModel.attributions);
|
|
54
|
+
}
|
|
55
|
+
if (shouldApplyProperty("label")) {
|
|
56
|
+
olLayer.set("label", layerModel.label);
|
|
57
|
+
}
|
|
58
|
+
// TODO: z-index
|
|
59
|
+
}
|
|
@@ -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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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") {
|
package/lib/map/create-map.ts
CHANGED
|
@@ -36,6 +36,10 @@ import {
|
|
|
36
36
|
tileLoadErrorCatchFunction,
|
|
37
37
|
} from "./handle-errors.js";
|
|
38
38
|
import VectorTile from "ol/source/VectorTile.js";
|
|
39
|
+
import {
|
|
40
|
+
canDoIncrementalUpdate,
|
|
41
|
+
updateLayerProperties,
|
|
42
|
+
} from "./layer-update.js";
|
|
39
43
|
|
|
40
44
|
const GEOJSON = new GeoJSON();
|
|
41
45
|
const WFS_MAX_FEATURES = 10000;
|
|
@@ -253,17 +257,34 @@ export async function createLayer(layerModel: MapContextLayer): Promise<Layer> {
|
|
|
253
257
|
if (!layer) {
|
|
254
258
|
throw new Error(`Layer could not be created for type: ${layerModel.type}`);
|
|
255
259
|
}
|
|
256
|
-
|
|
257
|
-
|
|
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);
|
|
260
|
+
|
|
261
|
+
updateLayerProperties(layerModel, layer);
|
|
263
262
|
|
|
264
263
|
return layer;
|
|
265
264
|
}
|
|
266
265
|
|
|
266
|
+
export function updateLayerInMap(
|
|
267
|
+
map: Map,
|
|
268
|
+
layerModel: MapContextLayer,
|
|
269
|
+
layerPosition: number,
|
|
270
|
+
previousLayerModel: MapContextLayer,
|
|
271
|
+
) {
|
|
272
|
+
const layers = map.getLayers();
|
|
273
|
+
const updatedLayer = layers.item(layerPosition) as Layer;
|
|
274
|
+
|
|
275
|
+
// if an incremental update is possible, do it to avoid costly layer recreation
|
|
276
|
+
if (canDoIncrementalUpdate(previousLayerModel, layerModel)) {
|
|
277
|
+
updateLayerProperties(layerModel, updatedLayer, previousLayerModel);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// dispose and recreate layer
|
|
282
|
+
updatedLayer.dispose();
|
|
283
|
+
createLayer(layerModel).then((layer) => {
|
|
284
|
+
layers.setAt(layerPosition, layer);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
267
288
|
export function createView(viewModel: MapContextView | null, map: Map): View {
|
|
268
289
|
if (viewModel === null) {
|
|
269
290
|
return new View({
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canDoIncrementalUpdate,
|
|
3
|
+
updateLayerProperties,
|
|
4
|
+
} from "./layer-update.js";
|
|
5
|
+
import { MapContextLayer } from "@geospatial-sdk/core";
|
|
6
|
+
import Layer from "ol/layer/Layer.js";
|
|
7
|
+
import { Source } from "ol/source.js";
|
|
8
|
+
import { SAMPLE_LAYER1 } from "@geospatial-sdk/core/fixtures/map-context.fixtures.js";
|
|
9
|
+
import VectorSource from "ol/source/Vector.js";
|
|
10
|
+
|
|
11
|
+
describe("Layer update utils", () => {
|
|
12
|
+
describe("canDoIncrementalUpdate", () => {
|
|
13
|
+
it("returns true if only updatable properties are changed", () => {
|
|
14
|
+
const oldLayer = {
|
|
15
|
+
name: "layer1",
|
|
16
|
+
type: "wms",
|
|
17
|
+
url: "https://example.com/wms",
|
|
18
|
+
opacity: 0.5,
|
|
19
|
+
visibility: true,
|
|
20
|
+
label: "Layer 1",
|
|
21
|
+
} as MapContextLayer;
|
|
22
|
+
const newLayer = {
|
|
23
|
+
name: "layer1",
|
|
24
|
+
type: "wms",
|
|
25
|
+
url: "https://example.com/wms",
|
|
26
|
+
opacity: 0.8,
|
|
27
|
+
label: "Layer 1 Updated",
|
|
28
|
+
extras: { hello: "world" },
|
|
29
|
+
} as MapContextLayer;
|
|
30
|
+
expect(canDoIncrementalUpdate(oldLayer, newLayer)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
it("returns false if non-updatable properties are changed", () => {
|
|
33
|
+
const oldLayer = {
|
|
34
|
+
name: "layer1",
|
|
35
|
+
type: "wms",
|
|
36
|
+
url: "https://example.com/wms",
|
|
37
|
+
opacity: 0.5,
|
|
38
|
+
visibility: true,
|
|
39
|
+
label: "Layer 1",
|
|
40
|
+
} as MapContextLayer;
|
|
41
|
+
const newLayer = {
|
|
42
|
+
name: "layer1",
|
|
43
|
+
type: "wms",
|
|
44
|
+
url: "https://example.com/wms/CHANGED",
|
|
45
|
+
opacity: 0.5,
|
|
46
|
+
visibility: true,
|
|
47
|
+
label: "Layer 1",
|
|
48
|
+
} as MapContextLayer;
|
|
49
|
+
expect(canDoIncrementalUpdate(oldLayer, newLayer)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("updateLayerProperties", () => {
|
|
54
|
+
let olLayer: Layer;
|
|
55
|
+
let olSource: Source;
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
olSource = new VectorSource({});
|
|
59
|
+
olLayer = new Layer({ source: olSource });
|
|
60
|
+
vi.spyOn(olLayer, "setVisible");
|
|
61
|
+
vi.spyOn(olLayer, "setOpacity");
|
|
62
|
+
vi.spyOn(olLayer, "set");
|
|
63
|
+
vi.spyOn(olSource, "setAttributions");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("applies the properties defined in the layer model", () => {
|
|
67
|
+
const layerModel = {
|
|
68
|
+
...SAMPLE_LAYER1,
|
|
69
|
+
visibility: false,
|
|
70
|
+
opacity: 0.7,
|
|
71
|
+
attributions: "hello world",
|
|
72
|
+
label: "Test Layer",
|
|
73
|
+
} as MapContextLayer;
|
|
74
|
+
updateLayerProperties(layerModel, olLayer);
|
|
75
|
+
expect(olLayer.setVisible).toHaveBeenCalledWith(false);
|
|
76
|
+
expect(olLayer.setOpacity).toHaveBeenCalledWith(0.7);
|
|
77
|
+
expect(olLayer.set).toHaveBeenCalledWith("label", "Test Layer");
|
|
78
|
+
expect(olSource.setAttributions).toHaveBeenCalledWith("hello world");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("does not apply properties not defined in the layer model", () => {
|
|
82
|
+
const layerModel = {
|
|
83
|
+
type: "wms",
|
|
84
|
+
url: "http://abc.org/wms",
|
|
85
|
+
name: "myLayer",
|
|
86
|
+
label: "Test Layer",
|
|
87
|
+
} as MapContextLayer;
|
|
88
|
+
updateLayerProperties(layerModel, olLayer);
|
|
89
|
+
expect(olLayer.setVisible).not.toHaveBeenCalled();
|
|
90
|
+
expect(olLayer.setOpacity).not.toHaveBeenCalled();
|
|
91
|
+
expect(olSource.setAttributions).not.toHaveBeenCalled();
|
|
92
|
+
expect(olLayer.set).toHaveBeenCalledWith("label", "Test Layer");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("applies properties if they have changed compared to the previous model and they are defined in the new model", () => {
|
|
96
|
+
const layerModel = {
|
|
97
|
+
...SAMPLE_LAYER1,
|
|
98
|
+
opacity: 0.9,
|
|
99
|
+
attributions: "hello world",
|
|
100
|
+
label: "Test Layer",
|
|
101
|
+
} as MapContextLayer;
|
|
102
|
+
const prevLayerModel = {
|
|
103
|
+
...SAMPLE_LAYER1,
|
|
104
|
+
visibility: true,
|
|
105
|
+
opacity: 0.7,
|
|
106
|
+
attributions: "hello world (old)",
|
|
107
|
+
} as MapContextLayer;
|
|
108
|
+
updateLayerProperties(layerModel, olLayer, prevLayerModel);
|
|
109
|
+
expect(olLayer.setVisible).not.toHaveBeenCalled();
|
|
110
|
+
expect(olLayer.setOpacity).toHaveBeenCalledWith(0.9);
|
|
111
|
+
expect(olSource.setAttributions).toHaveBeenCalledWith("hello world");
|
|
112
|
+
expect(olLayer.set).toHaveBeenCalledWith("label", "Test Layer");
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { getHash, MapContextLayer } from "@geospatial-sdk/core";
|
|
2
|
+
import { MapContextBaseLayer } from "@geospatial-sdk/core/lib/model/map-context.js";
|
|
3
|
+
import Layer from "ol/layer/Layer.js";
|
|
4
|
+
|
|
5
|
+
const UPDATABLE_PROPERTIES: (keyof MapContextBaseLayer)[] = [
|
|
6
|
+
"opacity",
|
|
7
|
+
"visibility",
|
|
8
|
+
"label",
|
|
9
|
+
"attributions",
|
|
10
|
+
"extras",
|
|
11
|
+
"version",
|
|
12
|
+
// TODO (when available) "zIndex"
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Incremental update is possible only if certain properties are changed: opacity,
|
|
17
|
+
* visibility, zIndex, etc.
|
|
18
|
+
*
|
|
19
|
+
* Note: we assume that both layers are different versions of the same layer (this
|
|
20
|
+
* will not be checked again)
|
|
21
|
+
* @param oldLayer
|
|
22
|
+
* @param newLayer
|
|
23
|
+
* @return Returns `true` if the only properties changed are the updatable ones
|
|
24
|
+
*/
|
|
25
|
+
export function canDoIncrementalUpdate(
|
|
26
|
+
oldLayer: MapContextLayer,
|
|
27
|
+
newLayer: MapContextLayer,
|
|
28
|
+
): boolean {
|
|
29
|
+
const oldHash = getHash(oldLayer, UPDATABLE_PROPERTIES);
|
|
30
|
+
const newHash = getHash(newLayer, UPDATABLE_PROPERTIES);
|
|
31
|
+
return oldHash === newHash;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Will apply generic properties to the layer; if a previous layer model is provided,
|
|
36
|
+
* only changed properties will be updated (to avoid costly change events in OpenLayers)
|
|
37
|
+
* @param layerModel
|
|
38
|
+
* @param olLayer
|
|
39
|
+
* @param previousLayerModel
|
|
40
|
+
*/
|
|
41
|
+
export function updateLayerProperties(
|
|
42
|
+
layerModel: MapContextLayer,
|
|
43
|
+
olLayer: Layer,
|
|
44
|
+
previousLayerModel?: MapContextLayer,
|
|
45
|
+
) {
|
|
46
|
+
function shouldApplyProperty(prop: keyof MapContextBaseLayer): boolean {
|
|
47
|
+
// if the new layer model does not define that property, skip it
|
|
48
|
+
// (setting or resetting it to a default value would be counter-intuitive)
|
|
49
|
+
if (!(prop in layerModel) || typeof layerModel[prop] === "undefined")
|
|
50
|
+
return false;
|
|
51
|
+
|
|
52
|
+
// if a previous model is provided and the value did not change in the new layer model, skip it
|
|
53
|
+
if (previousLayerModel && layerModel[prop] === previousLayerModel[prop]) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// any other case: apply the property
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
if (shouldApplyProperty("visibility")) {
|
|
61
|
+
olLayer.setVisible(layerModel.visibility!);
|
|
62
|
+
}
|
|
63
|
+
if (shouldApplyProperty("opacity")) {
|
|
64
|
+
olLayer.setOpacity(layerModel.opacity!);
|
|
65
|
+
}
|
|
66
|
+
if (shouldApplyProperty("attributions")) {
|
|
67
|
+
olLayer.getSource()?.setAttributions(layerModel.attributions);
|
|
68
|
+
}
|
|
69
|
+
if (shouldApplyProperty("label")) {
|
|
70
|
+
olLayer.set("label", layerModel.label);
|
|
71
|
+
}
|
|
72
|
+
// TODO: z-index
|
|
73
|
+
}
|
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.49+67854c5",
|
|
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.
|
|
40
|
+
"@geospatial-sdk/core": "^0.0.5-dev.49+67854c5",
|
|
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": "
|
|
45
|
+
"gitHead": "67854c5bbe5b473e1a8160f5e8e56fe162e1d427"
|
|
46
46
|
}
|