@geospatial-sdk/core 0.0.5-dev.45 → 0.0.5-dev.47
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/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/map-context-diff.js +1 -1
- package/dist/utils/map-context-layer.d.ts +13 -0
- package/dist/utils/map-context-layer.d.ts.map +1 -0
- package/dist/utils/map-context-layer.js +42 -0
- package/dist/utils/map-context.d.ts +24 -18
- package/dist/utils/map-context.d.ts.map +1 -1
- package/dist/utils/map-context.js +35 -33
- package/lib/utils/index.ts +2 -0
- package/lib/utils/map-context-diff.ts +1 -1
- package/lib/utils/map-context-layer.test.ts +351 -0
- package/lib/utils/map-context-layer.ts +63 -0
- package/lib/utils/map-context.test.ts +76 -305
- package/lib/utils/map-context.ts +41 -47
- package/package.json +2 -2
package/dist/utils/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./url.js";
|
|
|
6
6
|
export * from "./freeze.js";
|
|
7
7
|
export * from "./hash.js";
|
|
8
8
|
export { computeMapContextDiff } from "./map-context-diff.js";
|
|
9
|
-
export { getLayerPosition, addLayerToContext, removeLayerFromContext, replaceLayerInContext, changeLayerPositionInContext, } from "./map-context.js";
|
|
9
|
+
export { getLayerPosition, addLayerToContext, removeLayerFromContext, replaceLayerInContext, changeLayerPositionInContext, updateLayerInContext, } from "./map-context.js";
|
|
10
|
+
export { updateLayer } from "./map-context-layer.js";
|
|
10
11
|
export { createViewFromLayer } from "./view.js";
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,EAC5B,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -6,5 +6,6 @@ export * from "./url.js";
|
|
|
6
6
|
export * from "./freeze.js";
|
|
7
7
|
export * from "./hash.js";
|
|
8
8
|
export { computeMapContextDiff } from "./map-context-diff.js";
|
|
9
|
-
export { getLayerPosition, addLayerToContext, removeLayerFromContext, replaceLayerInContext, changeLayerPositionInContext, } from "./map-context.js";
|
|
9
|
+
export { getLayerPosition, addLayerToContext, removeLayerFromContext, replaceLayerInContext, changeLayerPositionInContext, updateLayerInContext, } from "./map-context.js";
|
|
10
|
+
export { updateLayer } from "./map-context-layer.js";
|
|
10
11
|
export { createViewFromLayer } from "./view.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isLayerSame, isLayerSameAndUnchanged } from "./map-context.js";
|
|
1
|
+
import { isLayerSame, isLayerSameAndUnchanged } from "./map-context-layer.js";
|
|
2
2
|
/**
|
|
3
3
|
* The following logic is produced by identifying layers in both context
|
|
4
4
|
* and determining whether they have been added, removed, changed or reordered.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MapContextLayer } from "../model/index.js";
|
|
2
|
+
export declare function getLayerHash(layer: MapContextLayer, includeExtras?: boolean): string;
|
|
3
|
+
export declare function isLayerSame(layerA: MapContextLayer, layerB: MapContextLayer): boolean;
|
|
4
|
+
export declare function isLayerSameAndUnchanged(layerA: MapContextLayer, layerB: MapContextLayer): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Applies the `updates` partial to the given layer. The layer will also be
|
|
7
|
+
* adjusted depending on the presence of the `id` and `version` fields.
|
|
8
|
+
* Note: any property set to `undefined` in `updates` will be removed from the resulting layer.
|
|
9
|
+
* @param layer
|
|
10
|
+
* @param updates
|
|
11
|
+
*/
|
|
12
|
+
export declare function updateLayer(layer: MapContextLayer, updates: Partial<MapContextLayer>): MapContextLayer;
|
|
13
|
+
//# sourceMappingURL=map-context-layer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map-context-layer.d.ts","sourceRoot":"","sources":["../../lib/utils/map-context-layer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,EACtB,aAAa,UAAQ,GACpB,MAAM,CAER;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,eAAe,GACtB,OAAO,CAKT;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,eAAe,GACtB,OAAO,CAST;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,eAAe,CAkBjB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { getHash } from "./hash.js";
|
|
2
|
+
export function getLayerHash(layer, includeExtras = false) {
|
|
3
|
+
return getHash(layer, includeExtras ? [] : ["extras"]);
|
|
4
|
+
}
|
|
5
|
+
export function isLayerSame(layerA, layerB) {
|
|
6
|
+
if ("id" in layerA && "id" in layerB) {
|
|
7
|
+
return layerA.id == layerB.id;
|
|
8
|
+
}
|
|
9
|
+
return getLayerHash(layerA) === getLayerHash(layerB);
|
|
10
|
+
}
|
|
11
|
+
export function isLayerSameAndUnchanged(layerA, layerB) {
|
|
12
|
+
if ("id" in layerA &&
|
|
13
|
+
"id" in layerB &&
|
|
14
|
+
("version" in layerA || "version" in layerB)) {
|
|
15
|
+
return layerA.id == layerB.id && layerA.version == layerB.version;
|
|
16
|
+
}
|
|
17
|
+
return getLayerHash(layerA, true) === getLayerHash(layerB, true);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Applies the `updates` partial to the given layer. The layer will also be
|
|
21
|
+
* adjusted depending on the presence of the `id` and `version` fields.
|
|
22
|
+
* Note: any property set to `undefined` in `updates` will be removed from the resulting layer.
|
|
23
|
+
* @param layer
|
|
24
|
+
* @param updates
|
|
25
|
+
*/
|
|
26
|
+
export function updateLayer(layer, updates) {
|
|
27
|
+
const updatedLayer = {
|
|
28
|
+
...layer,
|
|
29
|
+
...updates,
|
|
30
|
+
};
|
|
31
|
+
if ("id" in updatedLayer &&
|
|
32
|
+
"version" in updatedLayer &&
|
|
33
|
+
typeof updatedLayer.version === "number") {
|
|
34
|
+
updatedLayer.version = updatedLayer.version + 1;
|
|
35
|
+
}
|
|
36
|
+
for (const key in updatedLayer) {
|
|
37
|
+
if (updatedLayer[key] === undefined) {
|
|
38
|
+
delete updatedLayer[key];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return updatedLayer;
|
|
42
|
+
}
|
|
@@ -1,41 +1,47 @@
|
|
|
1
1
|
import { MapContext, MapContextLayer } from "../model/index.js";
|
|
2
|
-
export declare function getLayerHash(layer: MapContextLayer, includeExtras?: boolean): string;
|
|
3
|
-
export declare function isLayerSame(layerA: MapContextLayer, layerB: MapContextLayer): boolean;
|
|
4
|
-
export declare function isLayerSameAndUnchanged(layerA: MapContextLayer, layerB: MapContextLayer): boolean;
|
|
5
2
|
export declare function getLayerPosition(context: MapContext, layerModel: MapContextLayer): number;
|
|
6
3
|
/**
|
|
7
4
|
* Adds a layer to the context at a specific position or at the end if no position is specified.
|
|
8
5
|
*
|
|
9
|
-
* @param
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
12
|
-
* @returns
|
|
6
|
+
* @param context The current map context.
|
|
7
|
+
* @param layerModel The layer to be added.
|
|
8
|
+
* @param [position] The position at which to add the layer. If not specified, the layer is added at the end.
|
|
9
|
+
* @returns The new map context with the added layer.
|
|
13
10
|
*/
|
|
14
11
|
export declare function addLayerToContext(context: MapContext, layerModel: MapContextLayer, position?: number): MapContext;
|
|
15
12
|
/**
|
|
16
13
|
* Removes a layer from the context.
|
|
17
14
|
*
|
|
18
|
-
* @param
|
|
19
|
-
* @param
|
|
20
|
-
* @returns
|
|
15
|
+
* @param context The current map context.
|
|
16
|
+
* @param layerModel The layer to be removed.
|
|
17
|
+
* @returns The new map context without the removed layer.
|
|
21
18
|
*/
|
|
22
19
|
export declare function removeLayerFromContext(context: MapContext, layerModel: MapContextLayer): MapContext;
|
|
23
20
|
/**
|
|
24
21
|
* Replaces a layer in the context with a new layer.
|
|
25
22
|
*
|
|
26
|
-
* @param
|
|
27
|
-
* @param
|
|
28
|
-
* @param
|
|
29
|
-
* @returns
|
|
23
|
+
* @param context The current map context.
|
|
24
|
+
* @param layerModel The layer to be replaced.
|
|
25
|
+
* @param replacement The new layer that will replace the old one.
|
|
26
|
+
* @returns The new map context with the replaced layer.
|
|
30
27
|
*/
|
|
31
28
|
export declare function replaceLayerInContext(context: MapContext, layerModel: MapContextLayer, replacement: MapContextLayer): MapContext;
|
|
29
|
+
/**
|
|
30
|
+
* Replaces a layer in the context with a new layer.
|
|
31
|
+
*
|
|
32
|
+
* @param context The current map context.
|
|
33
|
+
* @param layerModel The layer to be replaced.
|
|
34
|
+
* @param layerUpdates The new layer that will replace the old one.
|
|
35
|
+
* @returns The new map context with the updated layer.
|
|
36
|
+
*/
|
|
37
|
+
export declare function updateLayerInContext(context: MapContext, layerModel: MapContextLayer, layerUpdates: Partial<MapContextLayer>): MapContext;
|
|
32
38
|
/**
|
|
33
39
|
* Changes the position of a layer in the context.
|
|
34
40
|
*
|
|
35
|
-
* @param
|
|
36
|
-
* @param
|
|
37
|
-
* @param
|
|
38
|
-
* @returns
|
|
41
|
+
* @param context The current map context.
|
|
42
|
+
* @param layerModel The layer whose position is to be changed.
|
|
43
|
+
* @param position The new position for the layer.
|
|
44
|
+
* @returns The new map context with the layer moved to the new position.
|
|
39
45
|
*/
|
|
40
46
|
export declare function changeLayerPositionInContext(context: MapContext, layerModel: MapContextLayer, position: number): MapContext;
|
|
41
47
|
//# sourceMappingURL=map-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map-context.d.ts","sourceRoot":"","sources":["../../lib/utils/map-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGhE,wBAAgB,
|
|
1
|
+
{"version":3,"file":"map-context.d.ts","sourceRoot":"","sources":["../../lib/utils/map-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGhE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,eAAe,GAC1B,MAAM,CAER;AAED;;;;;;;GAOG;AAEH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,eAAe,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,UAAU,CAQZ;AAED;;;;;;GAMG;AAEH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,eAAe,GAC1B,UAAU,CAOZ;AAED;;;;;;;GAOG;AAEH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,eAAe,EAC3B,WAAW,EAAE,eAAe,GAC3B,UAAU,CAOZ;AAED;;;;;;;GAOG;AAEH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,eAAe,EAC3B,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC,GACrC,UAAU,CAUZ;AAED;;;;;;;GAOG;AAEH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,eAAe,EAC3B,QAAQ,EAAE,MAAM,GACf,UAAU,CAGZ"}
|
|
@@ -1,31 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export function getLayerHash(layer, includeExtras = false) {
|
|
3
|
-
return getHash(layer, includeExtras ? [] : ["extras"]);
|
|
4
|
-
}
|
|
5
|
-
export function isLayerSame(layerA, layerB) {
|
|
6
|
-
if ("id" in layerA && "id" in layerB) {
|
|
7
|
-
return layerA.id == layerB.id;
|
|
8
|
-
}
|
|
9
|
-
return getLayerHash(layerA) === getLayerHash(layerB);
|
|
10
|
-
}
|
|
11
|
-
export function isLayerSameAndUnchanged(layerA, layerB) {
|
|
12
|
-
if ("id" in layerA &&
|
|
13
|
-
"id" in layerB &&
|
|
14
|
-
("version" in layerA || "version" in layerB)) {
|
|
15
|
-
return layerA.id == layerB.id && layerA.version == layerB.version;
|
|
16
|
-
}
|
|
17
|
-
return getLayerHash(layerA, true) === getLayerHash(layerB, true);
|
|
18
|
-
}
|
|
1
|
+
import { isLayerSame, updateLayer } from "./map-context-layer.js";
|
|
19
2
|
export function getLayerPosition(context, layerModel) {
|
|
20
3
|
return context.layers.findIndex((l) => isLayerSame(layerModel, l));
|
|
21
4
|
}
|
|
22
5
|
/**
|
|
23
6
|
* Adds a layer to the context at a specific position or at the end if no position is specified.
|
|
24
7
|
*
|
|
25
|
-
* @param
|
|
26
|
-
* @param
|
|
27
|
-
* @param
|
|
28
|
-
* @returns
|
|
8
|
+
* @param context The current map context.
|
|
9
|
+
* @param layerModel The layer to be added.
|
|
10
|
+
* @param [position] The position at which to add the layer. If not specified, the layer is added at the end.
|
|
11
|
+
* @returns The new map context with the added layer.
|
|
29
12
|
*/
|
|
30
13
|
export function addLayerToContext(context, layerModel, position) {
|
|
31
14
|
const newContext = { ...context, layers: [...context.layers] };
|
|
@@ -40,9 +23,9 @@ export function addLayerToContext(context, layerModel, position) {
|
|
|
40
23
|
/**
|
|
41
24
|
* Removes a layer from the context.
|
|
42
25
|
*
|
|
43
|
-
* @param
|
|
44
|
-
* @param
|
|
45
|
-
* @returns
|
|
26
|
+
* @param context The current map context.
|
|
27
|
+
* @param layerModel The layer to be removed.
|
|
28
|
+
* @returns The new map context without the removed layer.
|
|
46
29
|
*/
|
|
47
30
|
export function removeLayerFromContext(context, layerModel) {
|
|
48
31
|
const newContext = { ...context, layers: [...context.layers] };
|
|
@@ -55,10 +38,10 @@ export function removeLayerFromContext(context, layerModel) {
|
|
|
55
38
|
/**
|
|
56
39
|
* Replaces a layer in the context with a new layer.
|
|
57
40
|
*
|
|
58
|
-
* @param
|
|
59
|
-
* @param
|
|
60
|
-
* @param
|
|
61
|
-
* @returns
|
|
41
|
+
* @param context The current map context.
|
|
42
|
+
* @param layerModel The layer to be replaced.
|
|
43
|
+
* @param replacement The new layer that will replace the old one.
|
|
44
|
+
* @returns The new map context with the replaced layer.
|
|
62
45
|
*/
|
|
63
46
|
export function replaceLayerInContext(context, layerModel, replacement) {
|
|
64
47
|
const newContext = { ...context, layers: [...context.layers] };
|
|
@@ -68,13 +51,32 @@ export function replaceLayerInContext(context, layerModel, replacement) {
|
|
|
68
51
|
}
|
|
69
52
|
return newContext;
|
|
70
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Replaces a layer in the context with a new layer.
|
|
56
|
+
*
|
|
57
|
+
* @param context The current map context.
|
|
58
|
+
* @param layerModel The layer to be replaced.
|
|
59
|
+
* @param layerUpdates The new layer that will replace the old one.
|
|
60
|
+
* @returns The new map context with the updated layer.
|
|
61
|
+
*/
|
|
62
|
+
export function updateLayerInContext(context, layerModel, layerUpdates) {
|
|
63
|
+
const position = getLayerPosition(context, layerModel);
|
|
64
|
+
if (position >= 0) {
|
|
65
|
+
const existing = context.layers[getLayerPosition(context, layerModel)];
|
|
66
|
+
const updated = updateLayer(existing, layerUpdates);
|
|
67
|
+
return replaceLayerInContext(context, layerModel, updated);
|
|
68
|
+
}
|
|
69
|
+
// we're building a new context so that the reference is changed anyway; this is done to be
|
|
70
|
+
// consistent with other utilities that always change the context reference even if the layer wasn't found
|
|
71
|
+
return { ...context };
|
|
72
|
+
}
|
|
71
73
|
/**
|
|
72
74
|
* Changes the position of a layer in the context.
|
|
73
75
|
*
|
|
74
|
-
* @param
|
|
75
|
-
* @param
|
|
76
|
-
* @param
|
|
77
|
-
* @returns
|
|
76
|
+
* @param context The current map context.
|
|
77
|
+
* @param layerModel The layer whose position is to be changed.
|
|
78
|
+
* @param position The new position for the layer.
|
|
79
|
+
* @returns The new map context with the layer moved to the new position.
|
|
78
80
|
*/
|
|
79
81
|
export function changeLayerPositionInContext(context, layerModel, position) {
|
|
80
82
|
const newContext = removeLayerFromContext(context, layerModel);
|
package/lib/utils/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
MapContextLayerPositioned,
|
|
6
6
|
MapContextLayerReordered,
|
|
7
7
|
} from "../model/index.js";
|
|
8
|
-
import { isLayerSame, isLayerSameAndUnchanged } from "./map-context.js";
|
|
8
|
+
import { isLayerSame, isLayerSameAndUnchanged } from "./map-context-layer.js";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* The following logic is produced by identifying layers in both context
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { describe } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
getLayerHash,
|
|
4
|
+
isLayerSame,
|
|
5
|
+
isLayerSameAndUnchanged,
|
|
6
|
+
updateLayer,
|
|
7
|
+
} from "./map-context-layer.js";
|
|
8
|
+
import {
|
|
9
|
+
SAMPLE_LAYER1,
|
|
10
|
+
SAMPLE_LAYER2,
|
|
11
|
+
} from "../../fixtures/map-context.fixtures.js";
|
|
12
|
+
|
|
13
|
+
describe("Map context layer utils", () => {
|
|
14
|
+
describe("isLayerSame", () => {
|
|
15
|
+
describe("layers with id", () => {
|
|
16
|
+
it("compares non-strictly by id", () => {
|
|
17
|
+
expect(
|
|
18
|
+
isLayerSame(
|
|
19
|
+
{ ...SAMPLE_LAYER1, id: "a" },
|
|
20
|
+
{ ...SAMPLE_LAYER1, id: "b" },
|
|
21
|
+
),
|
|
22
|
+
).toBe(false);
|
|
23
|
+
expect(
|
|
24
|
+
isLayerSame(
|
|
25
|
+
{ ...SAMPLE_LAYER1, id: "ab" },
|
|
26
|
+
{ ...SAMPLE_LAYER2, id: "ab" },
|
|
27
|
+
),
|
|
28
|
+
).toBe(true);
|
|
29
|
+
expect(
|
|
30
|
+
isLayerSame(
|
|
31
|
+
{ ...SAMPLE_LAYER1, id: 1 },
|
|
32
|
+
{ ...SAMPLE_LAYER2, id: "01" },
|
|
33
|
+
),
|
|
34
|
+
).toBe(true);
|
|
35
|
+
expect(
|
|
36
|
+
isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER2, id: 1 }),
|
|
37
|
+
).toBe(true);
|
|
38
|
+
expect(
|
|
39
|
+
isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER1, id: 2 }),
|
|
40
|
+
).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe("layers without id", () => {
|
|
44
|
+
it("compares by properties", () => {
|
|
45
|
+
expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(true);
|
|
46
|
+
expect(
|
|
47
|
+
isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, name: "abc" }),
|
|
48
|
+
).toBe(false);
|
|
49
|
+
expect(
|
|
50
|
+
isLayerSame(
|
|
51
|
+
{
|
|
52
|
+
...SAMPLE_LAYER1,
|
|
53
|
+
url: "http://abc.org",
|
|
54
|
+
name: SAMPLE_LAYER1.name,
|
|
55
|
+
},
|
|
56
|
+
{ ...SAMPLE_LAYER1, url: "http://abc.org" },
|
|
57
|
+
),
|
|
58
|
+
).toBe(true);
|
|
59
|
+
expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
it("ignores extras prop", () => {
|
|
62
|
+
expect(
|
|
63
|
+
isLayerSame(SAMPLE_LAYER1, {
|
|
64
|
+
...SAMPLE_LAYER1,
|
|
65
|
+
extras: { otherProp: "abc" },
|
|
66
|
+
}),
|
|
67
|
+
).toBe(true);
|
|
68
|
+
expect(
|
|
69
|
+
isLayerSame(SAMPLE_LAYER1, {
|
|
70
|
+
...SAMPLE_LAYER1,
|
|
71
|
+
extras: undefined,
|
|
72
|
+
}),
|
|
73
|
+
).toBe(true);
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
75
|
+
const { extras, ...layer } = SAMPLE_LAYER1;
|
|
76
|
+
expect(isLayerSame(SAMPLE_LAYER1, layer)).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("layers with and without id", () => {
|
|
80
|
+
it("compares by properties", () => {
|
|
81
|
+
expect(
|
|
82
|
+
isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, id: "123" }),
|
|
83
|
+
).toBe(false);
|
|
84
|
+
expect(
|
|
85
|
+
isLayerSame(
|
|
86
|
+
{ ...SAMPLE_LAYER1, id: "123" },
|
|
87
|
+
{ id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
|
|
88
|
+
),
|
|
89
|
+
).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("isLayerSameAndUnchanged", () => {
|
|
95
|
+
describe("layers with id and version", () => {
|
|
96
|
+
it("compares non-strictly by id and version field", () => {
|
|
97
|
+
expect(
|
|
98
|
+
isLayerSameAndUnchanged(
|
|
99
|
+
{ ...SAMPLE_LAYER1, id: "ab", version: 2 },
|
|
100
|
+
{ ...SAMPLE_LAYER2, id: "ab", version: 2 },
|
|
101
|
+
),
|
|
102
|
+
).toBe(true);
|
|
103
|
+
expect(
|
|
104
|
+
isLayerSameAndUnchanged(
|
|
105
|
+
{ ...SAMPLE_LAYER1, id: "ab", version: 2 },
|
|
106
|
+
{ ...SAMPLE_LAYER1, id: "ab", version: 1 },
|
|
107
|
+
),
|
|
108
|
+
).toBe(false);
|
|
109
|
+
expect(
|
|
110
|
+
isLayerSameAndUnchanged(
|
|
111
|
+
{ ...SAMPLE_LAYER1, id: 1 },
|
|
112
|
+
{ ...SAMPLE_LAYER1, id: "01", version: 3 },
|
|
113
|
+
),
|
|
114
|
+
).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe("layers with id and both without version", () => {
|
|
118
|
+
it("compares by properties, including extras", () => {
|
|
119
|
+
expect(
|
|
120
|
+
isLayerSameAndUnchanged(
|
|
121
|
+
{ ...SAMPLE_LAYER1, id: "a" },
|
|
122
|
+
{ ...SAMPLE_LAYER1, id: "b" },
|
|
123
|
+
),
|
|
124
|
+
).toBe(false);
|
|
125
|
+
expect(
|
|
126
|
+
isLayerSameAndUnchanged(
|
|
127
|
+
{ ...SAMPLE_LAYER1, id: "a" },
|
|
128
|
+
{ ...SAMPLE_LAYER2, id: "a" },
|
|
129
|
+
),
|
|
130
|
+
).toBe(false);
|
|
131
|
+
expect(
|
|
132
|
+
isLayerSameAndUnchanged(
|
|
133
|
+
{ ...SAMPLE_LAYER1, id: "a" },
|
|
134
|
+
{ ...SAMPLE_LAYER1, id: "a" },
|
|
135
|
+
),
|
|
136
|
+
).toBe(true);
|
|
137
|
+
expect(
|
|
138
|
+
isLayerSameAndUnchanged(
|
|
139
|
+
{ ...SAMPLE_LAYER2, id: "b", extras: { hello: "world" } },
|
|
140
|
+
{ ...SAMPLE_LAYER2, id: "b", extras: { hello: "world" } },
|
|
141
|
+
),
|
|
142
|
+
).toBe(true);
|
|
143
|
+
expect(
|
|
144
|
+
isLayerSameAndUnchanged(
|
|
145
|
+
{ ...SAMPLE_LAYER2, id: "b", extras: { hello: "world" } },
|
|
146
|
+
{ ...SAMPLE_LAYER2, id: "b", extras: { foo: "bar" } },
|
|
147
|
+
),
|
|
148
|
+
).toBe(false);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe("layers without id", () => {
|
|
152
|
+
it("compares by properties, including extras", () => {
|
|
153
|
+
expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(
|
|
154
|
+
true,
|
|
155
|
+
);
|
|
156
|
+
expect(
|
|
157
|
+
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
158
|
+
...SAMPLE_LAYER1,
|
|
159
|
+
name: "abc",
|
|
160
|
+
}),
|
|
161
|
+
).toBe(false);
|
|
162
|
+
expect(
|
|
163
|
+
isLayerSameAndUnchanged(
|
|
164
|
+
{
|
|
165
|
+
...SAMPLE_LAYER1,
|
|
166
|
+
url: "http://abc.org",
|
|
167
|
+
name: SAMPLE_LAYER1.name,
|
|
168
|
+
},
|
|
169
|
+
{ ...SAMPLE_LAYER1, url: "http://abc.org" },
|
|
170
|
+
),
|
|
171
|
+
).toBe(true);
|
|
172
|
+
expect(
|
|
173
|
+
isLayerSameAndUnchanged(
|
|
174
|
+
{
|
|
175
|
+
...SAMPLE_LAYER1,
|
|
176
|
+
opacity: 1,
|
|
177
|
+
},
|
|
178
|
+
SAMPLE_LAYER1,
|
|
179
|
+
),
|
|
180
|
+
).toBe(false);
|
|
181
|
+
expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(
|
|
182
|
+
false,
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
it("takes into account extras prop", () => {
|
|
186
|
+
expect(
|
|
187
|
+
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
188
|
+
...SAMPLE_LAYER1,
|
|
189
|
+
extras: { otherProp: "abc" },
|
|
190
|
+
}),
|
|
191
|
+
).toBe(false);
|
|
192
|
+
expect(
|
|
193
|
+
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
194
|
+
...SAMPLE_LAYER1,
|
|
195
|
+
extras: undefined,
|
|
196
|
+
}),
|
|
197
|
+
).toBe(false);
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
199
|
+
const { extras, ...layer } = SAMPLE_LAYER1;
|
|
200
|
+
expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, layer)).toBe(false);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
describe("layers with and without id", () => {
|
|
204
|
+
it("compares by properties", () => {
|
|
205
|
+
expect(
|
|
206
|
+
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
207
|
+
...SAMPLE_LAYER1,
|
|
208
|
+
id: "123",
|
|
209
|
+
}),
|
|
210
|
+
).toBe(false);
|
|
211
|
+
expect(
|
|
212
|
+
isLayerSameAndUnchanged(
|
|
213
|
+
{ ...SAMPLE_LAYER1, id: "123" },
|
|
214
|
+
{ id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
|
|
215
|
+
),
|
|
216
|
+
).toBe(true);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe("getLayerHash", () => {
|
|
222
|
+
it("works with serializable entities", () => {
|
|
223
|
+
expect(
|
|
224
|
+
getLayerHash({
|
|
225
|
+
...SAMPLE_LAYER1,
|
|
226
|
+
extras: {
|
|
227
|
+
array: [11, 22, null, undefined],
|
|
228
|
+
object: {},
|
|
229
|
+
undef: undefined,
|
|
230
|
+
},
|
|
231
|
+
}),
|
|
232
|
+
).toBeTypeOf("string");
|
|
233
|
+
});
|
|
234
|
+
it("ignores extra property by default", () => {
|
|
235
|
+
expect(
|
|
236
|
+
getLayerHash({
|
|
237
|
+
...SAMPLE_LAYER1,
|
|
238
|
+
extras: {
|
|
239
|
+
array: [11, 22, null, undefined],
|
|
240
|
+
object: {},
|
|
241
|
+
},
|
|
242
|
+
}),
|
|
243
|
+
).toEqual(
|
|
244
|
+
getLayerHash({
|
|
245
|
+
...SAMPLE_LAYER1,
|
|
246
|
+
extras: { hello: "world" },
|
|
247
|
+
}),
|
|
248
|
+
);
|
|
249
|
+
});
|
|
250
|
+
it("works with non-serializable entities (but they are ignored)", () => {
|
|
251
|
+
const hash = getLayerHash(
|
|
252
|
+
{
|
|
253
|
+
...SAMPLE_LAYER1,
|
|
254
|
+
extras: {
|
|
255
|
+
func: () => 123,
|
|
256
|
+
canvas: document.createElement("canvas"),
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
true,
|
|
260
|
+
);
|
|
261
|
+
expect(hash).toBeTypeOf("string");
|
|
262
|
+
expect(hash).toEqual(
|
|
263
|
+
getLayerHash(
|
|
264
|
+
{
|
|
265
|
+
...SAMPLE_LAYER1,
|
|
266
|
+
extras: {
|
|
267
|
+
func: () => 456,
|
|
268
|
+
canvas: document.createElement("div"),
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
true,
|
|
272
|
+
),
|
|
273
|
+
);
|
|
274
|
+
expect(hash).not.toEqual(
|
|
275
|
+
getLayerHash(
|
|
276
|
+
{
|
|
277
|
+
...SAMPLE_LAYER1,
|
|
278
|
+
extras: {},
|
|
279
|
+
},
|
|
280
|
+
true,
|
|
281
|
+
),
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
it("does not take into account properties order", () => {
|
|
285
|
+
expect(
|
|
286
|
+
getLayerHash(
|
|
287
|
+
{
|
|
288
|
+
type: "wms",
|
|
289
|
+
url: "http://abc.org/wms",
|
|
290
|
+
name: "myLayer",
|
|
291
|
+
extras: {
|
|
292
|
+
array: [1, 2, 3],
|
|
293
|
+
object: {},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
true,
|
|
297
|
+
),
|
|
298
|
+
).toEqual(
|
|
299
|
+
getLayerHash(
|
|
300
|
+
{
|
|
301
|
+
extras: {
|
|
302
|
+
array: [1, 2, 3],
|
|
303
|
+
object: {},
|
|
304
|
+
},
|
|
305
|
+
url: "http://abc.org/wms",
|
|
306
|
+
type: "wms",
|
|
307
|
+
name: "myLayer",
|
|
308
|
+
},
|
|
309
|
+
true,
|
|
310
|
+
),
|
|
311
|
+
);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
describe("updateLayer", () => {
|
|
316
|
+
it("applies updates to a layer", () => {
|
|
317
|
+
const updated = updateLayer(SAMPLE_LAYER1, {
|
|
318
|
+
opacity: 0.9,
|
|
319
|
+
visibility: false,
|
|
320
|
+
});
|
|
321
|
+
expect(updated).toMatchObject({
|
|
322
|
+
...SAMPLE_LAYER1,
|
|
323
|
+
opacity: 0.9,
|
|
324
|
+
visibility: false,
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("does not modify the original layer", () => {
|
|
329
|
+
const updated = updateLayer(SAMPLE_LAYER1, { opacity: 0.5 });
|
|
330
|
+
expect(updated).not.toBe(SAMPLE_LAYER1);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("removes properties set to undefined", () => {
|
|
334
|
+
const layerWithOpacity = { ...SAMPLE_LAYER1, opacity: 0.8 };
|
|
335
|
+
const updated = updateLayer(layerWithOpacity, { opacity: undefined });
|
|
336
|
+
expect(updated).not.toHaveProperty("opacity");
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("increments version when layer has both id and version", () => {
|
|
340
|
+
const layer = { ...SAMPLE_LAYER1, id: "123", version: 0 };
|
|
341
|
+
const updated = updateLayer(layer, { opacity: 0.6 });
|
|
342
|
+
expect(updated.version).toBe(1);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("does not write version when layer only has id", () => {
|
|
346
|
+
const layer = { ...SAMPLE_LAYER1, id: "123" };
|
|
347
|
+
const updated = updateLayer(layer, { opacity: 0.6 });
|
|
348
|
+
expect(updated).not.toHaveProperty("version");
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { MapContextLayer } from "../model/index.js";
|
|
2
|
+
import { getHash } from "./hash.js";
|
|
3
|
+
|
|
4
|
+
export function getLayerHash(
|
|
5
|
+
layer: MapContextLayer,
|
|
6
|
+
includeExtras = false,
|
|
7
|
+
): string {
|
|
8
|
+
return getHash(layer, includeExtras ? [] : ["extras"]);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isLayerSame(
|
|
12
|
+
layerA: MapContextLayer,
|
|
13
|
+
layerB: MapContextLayer,
|
|
14
|
+
): boolean {
|
|
15
|
+
if ("id" in layerA && "id" in layerB) {
|
|
16
|
+
return layerA.id == layerB.id;
|
|
17
|
+
}
|
|
18
|
+
return getLayerHash(layerA) === getLayerHash(layerB);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isLayerSameAndUnchanged(
|
|
22
|
+
layerA: MapContextLayer,
|
|
23
|
+
layerB: MapContextLayer,
|
|
24
|
+
): boolean {
|
|
25
|
+
if (
|
|
26
|
+
"id" in layerA &&
|
|
27
|
+
"id" in layerB &&
|
|
28
|
+
("version" in layerA || "version" in layerB)
|
|
29
|
+
) {
|
|
30
|
+
return layerA.id == layerB.id && layerA.version == layerB.version;
|
|
31
|
+
}
|
|
32
|
+
return getLayerHash(layerA, true) === getLayerHash(layerB, true);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Applies the `updates` partial to the given layer. The layer will also be
|
|
37
|
+
* adjusted depending on the presence of the `id` and `version` fields.
|
|
38
|
+
* Note: any property set to `undefined` in `updates` will be removed from the resulting layer.
|
|
39
|
+
* @param layer
|
|
40
|
+
* @param updates
|
|
41
|
+
*/
|
|
42
|
+
export function updateLayer(
|
|
43
|
+
layer: MapContextLayer,
|
|
44
|
+
updates: Partial<MapContextLayer>,
|
|
45
|
+
): MapContextLayer {
|
|
46
|
+
const updatedLayer: MapContextLayer = {
|
|
47
|
+
...layer,
|
|
48
|
+
...updates,
|
|
49
|
+
} as MapContextLayer;
|
|
50
|
+
if (
|
|
51
|
+
"id" in updatedLayer &&
|
|
52
|
+
"version" in updatedLayer &&
|
|
53
|
+
typeof updatedLayer.version === "number"
|
|
54
|
+
) {
|
|
55
|
+
updatedLayer.version = updatedLayer.version + 1;
|
|
56
|
+
}
|
|
57
|
+
for (const key in updatedLayer) {
|
|
58
|
+
if (updatedLayer[key as keyof MapContextLayer] === undefined) {
|
|
59
|
+
delete updatedLayer[key as keyof MapContextLayer];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return updatedLayer;
|
|
63
|
+
}
|
|
@@ -2,14 +2,12 @@ import { describe } from "vitest";
|
|
|
2
2
|
import {
|
|
3
3
|
addLayerToContext,
|
|
4
4
|
changeLayerPositionInContext,
|
|
5
|
-
getLayerHash,
|
|
6
5
|
getLayerPosition,
|
|
7
|
-
isLayerSame,
|
|
8
|
-
isLayerSameAndUnchanged,
|
|
9
6
|
removeLayerFromContext,
|
|
10
7
|
replaceLayerInContext,
|
|
8
|
+
updateLayerInContext,
|
|
11
9
|
} from "./map-context.js";
|
|
12
|
-
import { MapContext } from "../model/index.js";
|
|
10
|
+
import { MapContext, MapContextLayer } from "../model/index.js";
|
|
13
11
|
import {
|
|
14
12
|
SAMPLE_CONTEXT,
|
|
15
13
|
SAMPLE_LAYER1,
|
|
@@ -18,307 +16,6 @@ import {
|
|
|
18
16
|
} from "../../fixtures/map-context.fixtures.js";
|
|
19
17
|
|
|
20
18
|
describe("Map context utils", () => {
|
|
21
|
-
describe("isLayerSame", () => {
|
|
22
|
-
describe("layers with id", () => {
|
|
23
|
-
it("compares non-strictly by id", () => {
|
|
24
|
-
expect(
|
|
25
|
-
isLayerSame(
|
|
26
|
-
{ ...SAMPLE_LAYER1, id: "a" },
|
|
27
|
-
{ ...SAMPLE_LAYER1, id: "b" },
|
|
28
|
-
),
|
|
29
|
-
).toBe(false);
|
|
30
|
-
expect(
|
|
31
|
-
isLayerSame(
|
|
32
|
-
{ ...SAMPLE_LAYER1, id: "ab" },
|
|
33
|
-
{ ...SAMPLE_LAYER2, id: "ab" },
|
|
34
|
-
),
|
|
35
|
-
).toBe(true);
|
|
36
|
-
expect(
|
|
37
|
-
isLayerSame(
|
|
38
|
-
{ ...SAMPLE_LAYER1, id: 1 },
|
|
39
|
-
{ ...SAMPLE_LAYER2, id: "01" },
|
|
40
|
-
),
|
|
41
|
-
).toBe(true);
|
|
42
|
-
expect(
|
|
43
|
-
isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER2, id: 1 }),
|
|
44
|
-
).toBe(true);
|
|
45
|
-
expect(
|
|
46
|
-
isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER1, id: 2 }),
|
|
47
|
-
).toBe(false);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe("layers without id", () => {
|
|
51
|
-
it("compares by properties", () => {
|
|
52
|
-
expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(true);
|
|
53
|
-
expect(
|
|
54
|
-
isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, name: "abc" }),
|
|
55
|
-
).toBe(false);
|
|
56
|
-
expect(
|
|
57
|
-
isLayerSame(
|
|
58
|
-
{
|
|
59
|
-
...SAMPLE_LAYER1,
|
|
60
|
-
url: "http://abc.org",
|
|
61
|
-
name: SAMPLE_LAYER1.name,
|
|
62
|
-
},
|
|
63
|
-
{ ...SAMPLE_LAYER1, url: "http://abc.org" },
|
|
64
|
-
),
|
|
65
|
-
).toBe(true);
|
|
66
|
-
expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(false);
|
|
67
|
-
});
|
|
68
|
-
it("ignores extras prop", () => {
|
|
69
|
-
expect(
|
|
70
|
-
isLayerSame(SAMPLE_LAYER1, {
|
|
71
|
-
...SAMPLE_LAYER1,
|
|
72
|
-
extras: { otherProp: "abc" },
|
|
73
|
-
}),
|
|
74
|
-
).toBe(true);
|
|
75
|
-
expect(
|
|
76
|
-
isLayerSame(SAMPLE_LAYER1, {
|
|
77
|
-
...SAMPLE_LAYER1,
|
|
78
|
-
extras: undefined,
|
|
79
|
-
}),
|
|
80
|
-
).toBe(true);
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
82
|
-
const { extras, ...layer } = SAMPLE_LAYER1;
|
|
83
|
-
expect(isLayerSame(SAMPLE_LAYER1, layer)).toBe(true);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
describe("layers with and without id", () => {
|
|
87
|
-
it("compares by properties", () => {
|
|
88
|
-
expect(
|
|
89
|
-
isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, id: "123" }),
|
|
90
|
-
).toBe(false);
|
|
91
|
-
expect(
|
|
92
|
-
isLayerSame(
|
|
93
|
-
{ ...SAMPLE_LAYER1, id: "123" },
|
|
94
|
-
{ id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
|
|
95
|
-
),
|
|
96
|
-
).toBe(true);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe("isLayerSameAndUnchanged", () => {
|
|
102
|
-
describe("layers with id and version", () => {
|
|
103
|
-
it("compares non-strictly by id and version field", () => {
|
|
104
|
-
expect(
|
|
105
|
-
isLayerSameAndUnchanged(
|
|
106
|
-
{ ...SAMPLE_LAYER1, id: "ab", version: 2 },
|
|
107
|
-
{ ...SAMPLE_LAYER2, id: "ab", version: 2 },
|
|
108
|
-
),
|
|
109
|
-
).toBe(true);
|
|
110
|
-
expect(
|
|
111
|
-
isLayerSameAndUnchanged(
|
|
112
|
-
{ ...SAMPLE_LAYER1, id: "ab", version: 2 },
|
|
113
|
-
{ ...SAMPLE_LAYER1, id: "ab", version: 1 },
|
|
114
|
-
),
|
|
115
|
-
).toBe(false);
|
|
116
|
-
expect(
|
|
117
|
-
isLayerSameAndUnchanged(
|
|
118
|
-
{ ...SAMPLE_LAYER1, id: 1 },
|
|
119
|
-
{ ...SAMPLE_LAYER1, id: "01", version: 3 },
|
|
120
|
-
),
|
|
121
|
-
).toBe(false);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
describe("layers with id and both without version", () => {
|
|
125
|
-
it("compares by properties, including extras", () => {
|
|
126
|
-
expect(
|
|
127
|
-
isLayerSameAndUnchanged(
|
|
128
|
-
{ ...SAMPLE_LAYER1, id: "a" },
|
|
129
|
-
{ ...SAMPLE_LAYER1, id: "b" },
|
|
130
|
-
),
|
|
131
|
-
).toBe(false);
|
|
132
|
-
expect(
|
|
133
|
-
isLayerSameAndUnchanged(
|
|
134
|
-
{ ...SAMPLE_LAYER1, id: "a" },
|
|
135
|
-
{ ...SAMPLE_LAYER2, id: "a" },
|
|
136
|
-
),
|
|
137
|
-
).toBe(false);
|
|
138
|
-
expect(
|
|
139
|
-
isLayerSameAndUnchanged(
|
|
140
|
-
{ ...SAMPLE_LAYER1, id: "a" },
|
|
141
|
-
{ ...SAMPLE_LAYER1, id: "a" },
|
|
142
|
-
),
|
|
143
|
-
).toBe(true);
|
|
144
|
-
expect(
|
|
145
|
-
isLayerSameAndUnchanged(
|
|
146
|
-
{ ...SAMPLE_LAYER2, id: "b", extras: { hello: "world" } },
|
|
147
|
-
{ ...SAMPLE_LAYER2, id: "b", extras: { hello: "world" } },
|
|
148
|
-
),
|
|
149
|
-
).toBe(true);
|
|
150
|
-
expect(
|
|
151
|
-
isLayerSameAndUnchanged(
|
|
152
|
-
{ ...SAMPLE_LAYER2, id: "b", extras: { hello: "world" } },
|
|
153
|
-
{ ...SAMPLE_LAYER2, id: "b", extras: { foo: "bar" } },
|
|
154
|
-
),
|
|
155
|
-
).toBe(false);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
describe("layers without id", () => {
|
|
159
|
-
it("compares by properties, including extras", () => {
|
|
160
|
-
expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(
|
|
161
|
-
true,
|
|
162
|
-
);
|
|
163
|
-
expect(
|
|
164
|
-
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
165
|
-
...SAMPLE_LAYER1,
|
|
166
|
-
name: "abc",
|
|
167
|
-
}),
|
|
168
|
-
).toBe(false);
|
|
169
|
-
expect(
|
|
170
|
-
isLayerSameAndUnchanged(
|
|
171
|
-
{
|
|
172
|
-
...SAMPLE_LAYER1,
|
|
173
|
-
url: "http://abc.org",
|
|
174
|
-
name: SAMPLE_LAYER1.name,
|
|
175
|
-
},
|
|
176
|
-
{ ...SAMPLE_LAYER1, url: "http://abc.org" },
|
|
177
|
-
),
|
|
178
|
-
).toBe(true);
|
|
179
|
-
expect(
|
|
180
|
-
isLayerSameAndUnchanged(
|
|
181
|
-
{
|
|
182
|
-
...SAMPLE_LAYER1,
|
|
183
|
-
opacity: 1,
|
|
184
|
-
},
|
|
185
|
-
SAMPLE_LAYER1,
|
|
186
|
-
),
|
|
187
|
-
).toBe(false);
|
|
188
|
-
expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(
|
|
189
|
-
false,
|
|
190
|
-
);
|
|
191
|
-
});
|
|
192
|
-
it("takes into account extras prop", () => {
|
|
193
|
-
expect(
|
|
194
|
-
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
195
|
-
...SAMPLE_LAYER1,
|
|
196
|
-
extras: { otherProp: "abc" },
|
|
197
|
-
}),
|
|
198
|
-
).toBe(false);
|
|
199
|
-
expect(
|
|
200
|
-
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
201
|
-
...SAMPLE_LAYER1,
|
|
202
|
-
extras: undefined,
|
|
203
|
-
}),
|
|
204
|
-
).toBe(false);
|
|
205
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
206
|
-
const { extras, ...layer } = SAMPLE_LAYER1;
|
|
207
|
-
expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, layer)).toBe(false);
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
describe("layers with and without id", () => {
|
|
211
|
-
it("compares by properties", () => {
|
|
212
|
-
expect(
|
|
213
|
-
isLayerSameAndUnchanged(SAMPLE_LAYER1, {
|
|
214
|
-
...SAMPLE_LAYER1,
|
|
215
|
-
id: "123",
|
|
216
|
-
}),
|
|
217
|
-
).toBe(false);
|
|
218
|
-
expect(
|
|
219
|
-
isLayerSameAndUnchanged(
|
|
220
|
-
{ ...SAMPLE_LAYER1, id: "123" },
|
|
221
|
-
{ id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
|
|
222
|
-
),
|
|
223
|
-
).toBe(true);
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
describe("getLayerHash", () => {
|
|
229
|
-
it("works with serializable entities", () => {
|
|
230
|
-
expect(
|
|
231
|
-
getLayerHash({
|
|
232
|
-
...SAMPLE_LAYER1,
|
|
233
|
-
extras: {
|
|
234
|
-
array: [11, 22, null, undefined],
|
|
235
|
-
object: {},
|
|
236
|
-
undef: undefined,
|
|
237
|
-
},
|
|
238
|
-
}),
|
|
239
|
-
).toBeTypeOf("string");
|
|
240
|
-
});
|
|
241
|
-
it("ignores extra property by default", () => {
|
|
242
|
-
expect(
|
|
243
|
-
getLayerHash({
|
|
244
|
-
...SAMPLE_LAYER1,
|
|
245
|
-
extras: {
|
|
246
|
-
array: [11, 22, null, undefined],
|
|
247
|
-
object: {},
|
|
248
|
-
},
|
|
249
|
-
}),
|
|
250
|
-
).toEqual(
|
|
251
|
-
getLayerHash({
|
|
252
|
-
...SAMPLE_LAYER1,
|
|
253
|
-
extras: { hello: "world" },
|
|
254
|
-
}),
|
|
255
|
-
);
|
|
256
|
-
});
|
|
257
|
-
it("works with non-serializable entities (but they are ignored)", () => {
|
|
258
|
-
const hash = getLayerHash(
|
|
259
|
-
{
|
|
260
|
-
...SAMPLE_LAYER1,
|
|
261
|
-
extras: {
|
|
262
|
-
func: () => 123,
|
|
263
|
-
canvas: document.createElement("canvas"),
|
|
264
|
-
},
|
|
265
|
-
},
|
|
266
|
-
true,
|
|
267
|
-
);
|
|
268
|
-
expect(hash).toBeTypeOf("string");
|
|
269
|
-
expect(hash).toEqual(
|
|
270
|
-
getLayerHash(
|
|
271
|
-
{
|
|
272
|
-
...SAMPLE_LAYER1,
|
|
273
|
-
extras: {
|
|
274
|
-
func: () => 456,
|
|
275
|
-
canvas: document.createElement("div"),
|
|
276
|
-
},
|
|
277
|
-
},
|
|
278
|
-
true,
|
|
279
|
-
),
|
|
280
|
-
);
|
|
281
|
-
expect(hash).not.toEqual(
|
|
282
|
-
getLayerHash(
|
|
283
|
-
{
|
|
284
|
-
...SAMPLE_LAYER1,
|
|
285
|
-
extras: {},
|
|
286
|
-
},
|
|
287
|
-
true,
|
|
288
|
-
),
|
|
289
|
-
);
|
|
290
|
-
});
|
|
291
|
-
it("does not take into account properties order", () => {
|
|
292
|
-
expect(
|
|
293
|
-
getLayerHash(
|
|
294
|
-
{
|
|
295
|
-
type: "wms",
|
|
296
|
-
url: "http://abc.org/wms",
|
|
297
|
-
name: "myLayer",
|
|
298
|
-
extras: {
|
|
299
|
-
array: [1, 2, 3],
|
|
300
|
-
object: {},
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
true,
|
|
304
|
-
),
|
|
305
|
-
).toEqual(
|
|
306
|
-
getLayerHash(
|
|
307
|
-
{
|
|
308
|
-
extras: {
|
|
309
|
-
array: [1, 2, 3],
|
|
310
|
-
object: {},
|
|
311
|
-
},
|
|
312
|
-
url: "http://abc.org/wms",
|
|
313
|
-
type: "wms",
|
|
314
|
-
name: "myLayer",
|
|
315
|
-
},
|
|
316
|
-
true,
|
|
317
|
-
),
|
|
318
|
-
);
|
|
319
|
-
});
|
|
320
|
-
});
|
|
321
|
-
|
|
322
19
|
describe("getLayerPosition", () => {
|
|
323
20
|
it("returns the index of the layer in the context", () => {
|
|
324
21
|
const context: MapContext = {
|
|
@@ -393,4 +90,78 @@ describe("Map context utils", () => {
|
|
|
393
90
|
expect(newContext.layers).toEqual([SAMPLE_LAYER2, SAMPLE_LAYER1]);
|
|
394
91
|
});
|
|
395
92
|
});
|
|
93
|
+
|
|
94
|
+
describe("updateLayerInContext", () => {
|
|
95
|
+
it("updates properties of a layer in the context (without id)", () => {
|
|
96
|
+
const context: MapContext = {
|
|
97
|
+
...SAMPLE_CONTEXT,
|
|
98
|
+
layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
|
|
99
|
+
};
|
|
100
|
+
const newContext = updateLayerInContext(context, SAMPLE_LAYER1, {
|
|
101
|
+
opacity: 0.8,
|
|
102
|
+
visibility: false,
|
|
103
|
+
});
|
|
104
|
+
expect(newContext.layers).toHaveLength(2);
|
|
105
|
+
expect(newContext.layers[0]).toEqual({
|
|
106
|
+
...SAMPLE_LAYER1,
|
|
107
|
+
opacity: 0.8,
|
|
108
|
+
visibility: false,
|
|
109
|
+
});
|
|
110
|
+
expect(newContext.layers[1]).toBe(SAMPLE_LAYER2);
|
|
111
|
+
});
|
|
112
|
+
it("does not modify the original context", () => {
|
|
113
|
+
const context: MapContext = {
|
|
114
|
+
...SAMPLE_CONTEXT,
|
|
115
|
+
layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
|
|
116
|
+
};
|
|
117
|
+
const newContext = updateLayerInContext(context, SAMPLE_LAYER1, {
|
|
118
|
+
opacity: 0.8,
|
|
119
|
+
visibility: false,
|
|
120
|
+
});
|
|
121
|
+
expect(newContext).not.toBe(context);
|
|
122
|
+
expect(newContext.layers).not.toBe(context.layers);
|
|
123
|
+
});
|
|
124
|
+
it("updates properties of a layer with id in the context", () => {
|
|
125
|
+
const context: MapContext = {
|
|
126
|
+
...SAMPLE_CONTEXT,
|
|
127
|
+
layers: [
|
|
128
|
+
SAMPLE_LAYER1,
|
|
129
|
+
SAMPLE_LAYER2,
|
|
130
|
+
{ ...SAMPLE_LAYER3, id: "myLayer", version: 3 },
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
const newContext = updateLayerInContext(
|
|
134
|
+
context,
|
|
135
|
+
// this is an empty layer that should not be used because we should track the layer by id in the context
|
|
136
|
+
{
|
|
137
|
+
id: "myLayer",
|
|
138
|
+
} as MapContextLayer,
|
|
139
|
+
{
|
|
140
|
+
opacity: 0.8,
|
|
141
|
+
visibility: false,
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
expect(newContext.layers).toHaveLength(3);
|
|
145
|
+
expect(newContext.layers[2]).toEqual({
|
|
146
|
+
...SAMPLE_LAYER3,
|
|
147
|
+
id: "myLayer",
|
|
148
|
+
version: 4,
|
|
149
|
+
opacity: 0.8,
|
|
150
|
+
visibility: false,
|
|
151
|
+
});
|
|
152
|
+
expect(newContext.layers[0]).toBe(SAMPLE_LAYER1);
|
|
153
|
+
expect(newContext.layers[1]).toBe(SAMPLE_LAYER2);
|
|
154
|
+
});
|
|
155
|
+
it("changes the context ref even if the layer is not found (the layers array is untouched)", () => {
|
|
156
|
+
const context: MapContext = {
|
|
157
|
+
...SAMPLE_CONTEXT,
|
|
158
|
+
layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
|
|
159
|
+
};
|
|
160
|
+
const newContext = updateLayerInContext(context, SAMPLE_LAYER3, {
|
|
161
|
+
opacity: 0.8,
|
|
162
|
+
});
|
|
163
|
+
expect(newContext).not.toBe(context);
|
|
164
|
+
expect(newContext.layers).toBe(context.layers);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
396
167
|
});
|
package/lib/utils/map-context.ts
CHANGED
|
@@ -1,36 +1,5 @@
|
|
|
1
1
|
import { MapContext, MapContextLayer } from "../model/index.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export function getLayerHash(
|
|
5
|
-
layer: MapContextLayer,
|
|
6
|
-
includeExtras = false,
|
|
7
|
-
): string {
|
|
8
|
-
return getHash(layer, includeExtras ? [] : ["extras"]);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function isLayerSame(
|
|
12
|
-
layerA: MapContextLayer,
|
|
13
|
-
layerB: MapContextLayer,
|
|
14
|
-
): boolean {
|
|
15
|
-
if ("id" in layerA && "id" in layerB) {
|
|
16
|
-
return layerA.id == layerB.id;
|
|
17
|
-
}
|
|
18
|
-
return getLayerHash(layerA) === getLayerHash(layerB);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function isLayerSameAndUnchanged(
|
|
22
|
-
layerA: MapContextLayer,
|
|
23
|
-
layerB: MapContextLayer,
|
|
24
|
-
): boolean {
|
|
25
|
-
if (
|
|
26
|
-
"id" in layerA &&
|
|
27
|
-
"id" in layerB &&
|
|
28
|
-
("version" in layerA || "version" in layerB)
|
|
29
|
-
) {
|
|
30
|
-
return layerA.id == layerB.id && layerA.version == layerB.version;
|
|
31
|
-
}
|
|
32
|
-
return getLayerHash(layerA, true) === getLayerHash(layerB, true);
|
|
33
|
-
}
|
|
2
|
+
import { isLayerSame, updateLayer } from "./map-context-layer.js";
|
|
34
3
|
|
|
35
4
|
export function getLayerPosition(
|
|
36
5
|
context: MapContext,
|
|
@@ -42,10 +11,10 @@ export function getLayerPosition(
|
|
|
42
11
|
/**
|
|
43
12
|
* Adds a layer to the context at a specific position or at the end if no position is specified.
|
|
44
13
|
*
|
|
45
|
-
* @param
|
|
46
|
-
* @param
|
|
47
|
-
* @param
|
|
48
|
-
* @returns
|
|
14
|
+
* @param context The current map context.
|
|
15
|
+
* @param layerModel The layer to be added.
|
|
16
|
+
* @param [position] The position at which to add the layer. If not specified, the layer is added at the end.
|
|
17
|
+
* @returns The new map context with the added layer.
|
|
49
18
|
*/
|
|
50
19
|
|
|
51
20
|
export function addLayerToContext(
|
|
@@ -65,9 +34,9 @@ export function addLayerToContext(
|
|
|
65
34
|
/**
|
|
66
35
|
* Removes a layer from the context.
|
|
67
36
|
*
|
|
68
|
-
* @param
|
|
69
|
-
* @param
|
|
70
|
-
* @returns
|
|
37
|
+
* @param context The current map context.
|
|
38
|
+
* @param layerModel The layer to be removed.
|
|
39
|
+
* @returns The new map context without the removed layer.
|
|
71
40
|
*/
|
|
72
41
|
|
|
73
42
|
export function removeLayerFromContext(
|
|
@@ -85,10 +54,10 @@ export function removeLayerFromContext(
|
|
|
85
54
|
/**
|
|
86
55
|
* Replaces a layer in the context with a new layer.
|
|
87
56
|
*
|
|
88
|
-
* @param
|
|
89
|
-
* @param
|
|
90
|
-
* @param
|
|
91
|
-
* @returns
|
|
57
|
+
* @param context The current map context.
|
|
58
|
+
* @param layerModel The layer to be replaced.
|
|
59
|
+
* @param replacement The new layer that will replace the old one.
|
|
60
|
+
* @returns The new map context with the replaced layer.
|
|
92
61
|
*/
|
|
93
62
|
|
|
94
63
|
export function replaceLayerInContext(
|
|
@@ -104,13 +73,38 @@ export function replaceLayerInContext(
|
|
|
104
73
|
return newContext;
|
|
105
74
|
}
|
|
106
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Replaces a layer in the context with a new layer.
|
|
78
|
+
*
|
|
79
|
+
* @param context The current map context.
|
|
80
|
+
* @param layerModel The layer to be replaced.
|
|
81
|
+
* @param layerUpdates The new layer that will replace the old one.
|
|
82
|
+
* @returns The new map context with the updated layer.
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
export function updateLayerInContext(
|
|
86
|
+
context: MapContext,
|
|
87
|
+
layerModel: MapContextLayer,
|
|
88
|
+
layerUpdates: Partial<MapContextLayer>,
|
|
89
|
+
): MapContext {
|
|
90
|
+
const position = getLayerPosition(context, layerModel);
|
|
91
|
+
if (position >= 0) {
|
|
92
|
+
const existing = context.layers[getLayerPosition(context, layerModel)];
|
|
93
|
+
const updated = updateLayer(existing, layerUpdates);
|
|
94
|
+
return replaceLayerInContext(context, layerModel, updated);
|
|
95
|
+
}
|
|
96
|
+
// we're building a new context so that the reference is changed anyway; this is done to be
|
|
97
|
+
// consistent with other utilities that always change the context reference even if the layer wasn't found
|
|
98
|
+
return { ...context };
|
|
99
|
+
}
|
|
100
|
+
|
|
107
101
|
/**
|
|
108
102
|
* Changes the position of a layer in the context.
|
|
109
103
|
*
|
|
110
|
-
* @param
|
|
111
|
-
* @param
|
|
112
|
-
* @param
|
|
113
|
-
* @returns
|
|
104
|
+
* @param context The current map context.
|
|
105
|
+
* @param layerModel The layer whose position is to be changed.
|
|
106
|
+
* @param position The new position for the layer.
|
|
107
|
+
* @returns The new map context with the layer moved to the new position.
|
|
114
108
|
*/
|
|
115
109
|
|
|
116
110
|
export function changeLayerPositionInContext(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geospatial-sdk/core",
|
|
3
|
-
"version": "0.0.5-dev.
|
|
3
|
+
"version": "0.0.5-dev.47+37669e8",
|
|
4
4
|
"description": "Core functions and models for the SDK",
|
|
5
5
|
"author": "Olivia <olivia.guyot@camptocamp.com>",
|
|
6
6
|
"homepage": "",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"test": "vitest",
|
|
23
23
|
"build": "tsc"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "37669e815765d751c4795a67e671ae19e3bf5a92",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"proj4": "^2.9.2"
|
|
28
28
|
},
|