@geospatial-sdk/core 0.0.5-dev.0 → 0.0.5-dev.0.sha-bfaf14b

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.
Files changed (67) hide show
  1. package/README.md +38 -5
  2. package/dist/constant/projections.d.ts +2 -0
  3. package/dist/constant/projections.d.ts.map +1 -0
  4. package/dist/constant/projections.js +1 -0
  5. package/dist/index.d.ts +7 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +7 -3
  8. package/dist/model/events.d.ts +86 -0
  9. package/dist/model/events.d.ts.map +1 -0
  10. package/dist/model/events.js +37 -0
  11. package/dist/model/index.d.ts +9 -2
  12. package/dist/model/index.d.ts.map +1 -1
  13. package/dist/model/index.js +9 -2
  14. package/dist/model/map-context-diff.d.ts +11 -3
  15. package/dist/model/map-context-diff.d.ts.map +1 -1
  16. package/dist/model/map-context.d.ts +174 -22
  17. package/dist/model/map-context.d.ts.map +1 -1
  18. package/dist/model/resolved-map-state.d.ts +49 -0
  19. package/dist/model/resolved-map-state.d.ts.map +1 -0
  20. package/dist/model/resolved-map-state.js +1 -0
  21. package/dist/model/style.d.ts +3 -0
  22. package/dist/model/style.d.ts.map +1 -0
  23. package/dist/model/style.js +1 -0
  24. package/dist/utils/hash.d.ts +2 -0
  25. package/dist/utils/hash.d.ts.map +1 -0
  26. package/dist/utils/hash.js +28 -0
  27. package/dist/utils/index.d.ts +12 -4
  28. package/dist/utils/index.d.ts.map +1 -1
  29. package/dist/utils/index.js +12 -4
  30. package/dist/utils/map-context-diff.d.ts +1 -1
  31. package/dist/utils/map-context-diff.d.ts.map +1 -1
  32. package/dist/utils/map-context-diff.js +19 -11
  33. package/dist/utils/map-context-layer.d.ts +13 -0
  34. package/dist/utils/map-context-layer.d.ts.map +1 -0
  35. package/dist/utils/map-context-layer.js +44 -0
  36. package/dist/utils/map-context.d.ts +48 -4
  37. package/dist/utils/map-context.d.ts.map +1 -1
  38. package/dist/utils/map-context.js +80 -29
  39. package/dist/utils/style.d.ts +4 -0
  40. package/dist/utils/style.d.ts.map +1 -0
  41. package/dist/utils/style.js +68 -0
  42. package/dist/utils/view.d.ts +25 -0
  43. package/dist/utils/view.d.ts.map +1 -0
  44. package/dist/utils/view.js +126 -0
  45. package/lib/constant/projections.ts +1 -0
  46. package/lib/index.ts +8 -3
  47. package/lib/model/events.ts +113 -0
  48. package/lib/model/index.ts +10 -2
  49. package/lib/model/map-context-diff.ts +12 -3
  50. package/lib/model/map-context.ts +219 -26
  51. package/lib/model/resolved-map-state.ts +67 -0
  52. package/lib/model/style.ts +3 -0
  53. package/lib/utils/freeze.test.ts +1 -1
  54. package/lib/utils/hash.test.ts +180 -0
  55. package/lib/utils/hash.ts +28 -0
  56. package/lib/utils/index.ts +20 -4
  57. package/lib/utils/map-context-diff.test.ts +240 -10
  58. package/lib/utils/map-context-diff.ts +23 -14
  59. package/lib/utils/map-context-layer.test.ts +357 -0
  60. package/lib/utils/map-context-layer.ts +66 -0
  61. package/lib/utils/map-context.test.ts +136 -272
  62. package/lib/utils/map-context.ts +108 -39
  63. package/lib/utils/style.ts +71 -0
  64. package/lib/utils/url.test.ts +1 -1
  65. package/lib/utils/view.test.ts +146 -0
  66. package/lib/utils/view.ts +163 -0
  67. package/package.json +20 -3
@@ -1,303 +1,167 @@
1
1
  import { describe } from "vitest";
2
2
  import {
3
- getLayerHash,
3
+ addLayerToContext,
4
+ changeLayerPositionInContext,
4
5
  getLayerPosition,
5
- isLayerSame,
6
- isLayerSameAndUnchanged,
7
- } from "./map-context";
8
- import { MapContext } from "../model";
6
+ removeLayerFromContext,
7
+ replaceLayerInContext,
8
+ updateLayerInContext,
9
+ } from "./map-context.js";
10
+ import { MapContext, MapContextLayer } from "../model/index.js";
9
11
  import {
10
12
  SAMPLE_CONTEXT,
11
13
  SAMPLE_LAYER1,
12
14
  SAMPLE_LAYER2,
13
- } from "../../fixtures/map-context.fixtures";
15
+ SAMPLE_LAYER3,
16
+ } from "../../fixtures/map-context.fixtures.js";
14
17
 
15
18
  describe("Map context utils", () => {
16
- describe("isLayerSame", () => {
17
- describe("layers with id", () => {
18
- it("compares non-strictly by id", () => {
19
- expect(
20
- isLayerSame(
21
- { ...SAMPLE_LAYER1, id: "a" },
22
- { ...SAMPLE_LAYER1, id: "b" },
23
- ),
24
- ).toBe(false);
25
- expect(
26
- isLayerSame(
27
- { ...SAMPLE_LAYER1, id: "ab" },
28
- { ...SAMPLE_LAYER2, id: "ab" },
29
- ),
30
- ).toBe(true);
31
- expect(
32
- isLayerSame(
33
- { ...SAMPLE_LAYER1, id: 1 },
34
- { ...SAMPLE_LAYER2, id: "01" },
35
- ),
36
- ).toBe(true);
37
- expect(
38
- isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER2, id: 1 }),
39
- ).toBe(true);
40
- expect(
41
- isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER1, id: 2 }),
42
- ).toBe(false);
43
- });
19
+ describe("getLayerPosition", () => {
20
+ it("returns the index of the layer in the context", () => {
21
+ const context: MapContext = {
22
+ ...SAMPLE_CONTEXT,
23
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
24
+ };
25
+ expect(getLayerPosition(context, SAMPLE_LAYER1)).toBe(0);
26
+ expect(getLayerPosition(context, SAMPLE_LAYER2)).toBe(1);
44
27
  });
45
- describe("layers without id", () => {
46
- it("compares by properties", () => {
47
- expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(true);
48
- expect(
49
- isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, name: "abc" }),
50
- ).toBe(false);
51
- expect(
52
- isLayerSame(
53
- {
54
- ...SAMPLE_LAYER1,
55
- url: "http://abc.org",
56
- name: SAMPLE_LAYER1.name,
57
- },
58
- { ...SAMPLE_LAYER1, url: "http://abc.org" },
59
- ),
60
- ).toBe(true);
61
- expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(false);
62
- });
63
- it("ignores extras prop", () => {
64
- expect(
65
- isLayerSame(SAMPLE_LAYER1, {
66
- ...SAMPLE_LAYER1,
67
- extras: { otherProp: "abc" },
68
- }),
69
- ).toBe(true);
70
- expect(
71
- isLayerSame(SAMPLE_LAYER1, {
72
- ...SAMPLE_LAYER1,
73
- extras: undefined,
74
- }),
75
- ).toBe(true);
76
- const { extras, ...layer } = SAMPLE_LAYER1;
77
- expect(isLayerSame(SAMPLE_LAYER1, layer)).toBe(true);
78
- });
28
+ });
29
+ describe("addLayerToContext", () => {
30
+ it("adds a layer to the context", () => {
31
+ const context: MapContext = {
32
+ ...SAMPLE_CONTEXT,
33
+ layers: [SAMPLE_LAYER1],
34
+ };
35
+ const newLayer = { ...SAMPLE_LAYER2, name: "newLayer" };
36
+ const newContext = addLayerToContext(context, newLayer);
37
+ expect(newContext.layers).toEqual([SAMPLE_LAYER1, newLayer]);
79
38
  });
80
- describe("layers with and without id", () => {
81
- it("compares by properties", () => {
82
- expect(
83
- isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, id: "123" }),
84
- ).toBe(false);
85
- expect(
86
- isLayerSame(
87
- { ...SAMPLE_LAYER1, id: "123" },
88
- { id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
89
- ),
90
- ).toBe(true);
91
- });
39
+ it("adds a layer at a specific position", () => {
40
+ const context: MapContext = {
41
+ ...SAMPLE_CONTEXT,
42
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
43
+ };
44
+ const newLayer = { ...SAMPLE_LAYER2, name: "newLayer" };
45
+ const newContext = addLayerToContext(context, newLayer, 1);
46
+ expect(newContext.layers).toEqual([
47
+ SAMPLE_LAYER1,
48
+ newLayer,
49
+ SAMPLE_LAYER2,
50
+ ]);
92
51
  });
93
52
  });
94
-
95
- describe("isLayerSameAndUnchanged", () => {
96
- describe("layers with id", () => {
97
- it("compares non-strictly by id and version field", () => {
98
- expect(
99
- isLayerSameAndUnchanged(
100
- { ...SAMPLE_LAYER1, id: "a" },
101
- { ...SAMPLE_LAYER1, id: "b" },
102
- ),
103
- ).toBe(false);
104
- expect(
105
- isLayerSameAndUnchanged(
106
- { ...SAMPLE_LAYER1, id: "a" },
107
- { ...SAMPLE_LAYER2, id: "a" },
108
- ),
109
- ).toBe(true);
110
- expect(
111
- isLayerSameAndUnchanged(
112
- { ...SAMPLE_LAYER1, id: "ab", version: 2 },
113
- { ...SAMPLE_LAYER2, id: "ab", version: 2 },
114
- ),
115
- ).toBe(true);
116
- expect(
117
- isLayerSameAndUnchanged(
118
- { ...SAMPLE_LAYER1, id: "ab", version: 2 },
119
- { ...SAMPLE_LAYER1, id: "ab", version: 1 },
120
- ),
121
- ).toBe(false);
122
- expect(
123
- isLayerSameAndUnchanged(
124
- { ...SAMPLE_LAYER1, id: 1 },
125
- { ...SAMPLE_LAYER1, id: "01", version: 3 },
126
- ),
127
- ).toBe(false);
128
- });
53
+ describe("removeLayerFromContext", () => {
54
+ it("removes a layer from the context", () => {
55
+ const context: MapContext = {
56
+ ...SAMPLE_CONTEXT,
57
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
58
+ };
59
+ const newContext = removeLayerFromContext(context, SAMPLE_LAYER1);
60
+ expect(newContext.layers).toEqual([SAMPLE_LAYER2]);
129
61
  });
130
- describe("layers without id", () => {
131
- it("compares by properties, including extras", () => {
132
- expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(
133
- true,
134
- );
135
- expect(
136
- isLayerSameAndUnchanged(SAMPLE_LAYER1, {
137
- ...SAMPLE_LAYER1,
138
- name: "abc",
139
- }),
140
- ).toBe(false);
141
- expect(
142
- isLayerSameAndUnchanged(
143
- {
144
- ...SAMPLE_LAYER1,
145
- url: "http://abc.org",
146
- name: SAMPLE_LAYER1.name,
147
- },
148
- { ...SAMPLE_LAYER1, url: "http://abc.org" },
149
- ),
150
- ).toBe(true);
151
- expect(
152
- isLayerSameAndUnchanged(
153
- {
154
- ...SAMPLE_LAYER1,
155
- opacity: 1,
156
- },
157
- SAMPLE_LAYER1,
158
- ),
159
- ).toBe(false);
160
- expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(
161
- false,
162
- );
163
- });
164
- it("takes into account extras prop", () => {
165
- expect(
166
- isLayerSameAndUnchanged(SAMPLE_LAYER1, {
167
- ...SAMPLE_LAYER1,
168
- extras: { otherProp: "abc" },
169
- }),
170
- ).toBe(false);
171
- expect(
172
- isLayerSameAndUnchanged(SAMPLE_LAYER1, {
173
- ...SAMPLE_LAYER1,
174
- extras: undefined,
175
- }),
176
- ).toBe(false);
177
- const { extras, ...layer } = SAMPLE_LAYER1;
178
- expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, layer)).toBe(false);
179
- });
62
+ });
63
+ describe("replaceLayerInContext", () => {
64
+ it("replaces a layer in the context", () => {
65
+ const context: MapContext = {
66
+ ...SAMPLE_CONTEXT,
67
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
68
+ };
69
+ const replacementLayer = { ...SAMPLE_LAYER3 };
70
+ const existingLayer = { ...SAMPLE_LAYER1 };
71
+ const newContext = replaceLayerInContext(
72
+ context,
73
+ existingLayer,
74
+ replacementLayer,
75
+ );
76
+ expect(newContext.layers).toEqual([replacementLayer, SAMPLE_LAYER2]);
180
77
  });
181
- describe("layers with and without id", () => {
182
- it("compares by properties", () => {
183
- expect(
184
- isLayerSameAndUnchanged(SAMPLE_LAYER1, {
185
- ...SAMPLE_LAYER1,
186
- id: "123",
187
- }),
188
- ).toBe(false);
189
- expect(
190
- isLayerSameAndUnchanged(
191
- { ...SAMPLE_LAYER1, id: "123" },
192
- { id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
193
- ),
194
- ).toBe(true);
195
- });
78
+ });
79
+ describe("changeLayerPositionInContext", () => {
80
+ it("changes the position of a layer in the context", () => {
81
+ const context: MapContext = {
82
+ ...SAMPLE_CONTEXT,
83
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
84
+ };
85
+ const newContext = changeLayerPositionInContext(
86
+ context,
87
+ SAMPLE_LAYER1,
88
+ 1,
89
+ );
90
+ expect(newContext.layers).toEqual([SAMPLE_LAYER2, SAMPLE_LAYER1]);
196
91
  });
197
92
  });
198
93
 
199
- describe("getLayerHash", () => {
200
- it("works with serializable entities", () => {
201
- expect(
202
- getLayerHash({
203
- ...SAMPLE_LAYER1,
204
- extras: {
205
- array: [11, 22, null, undefined],
206
- object: {},
207
- undef: undefined,
208
- },
209
- }),
210
- ).toBeTypeOf("string");
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);
211
111
  });
212
- it("ignores extra property by default", () => {
213
- expect(
214
- getLayerHash({
215
- ...SAMPLE_LAYER1,
216
- extras: {
217
- array: [11, 22, null, undefined],
218
- object: {},
219
- },
220
- }),
221
- ).toEqual(
222
- getLayerHash({
223
- ...SAMPLE_LAYER1,
224
- extras: { hello: "world" },
225
- }),
226
- );
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);
227
123
  });
228
- it("works with non-serializable entities (but they are ignored)", () => {
229
- const hash = getLayerHash(
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,
230
139
  {
231
- ...SAMPLE_LAYER1,
232
- extras: {
233
- func: () => 123,
234
- canvas: document.createElement("canvas"),
235
- },
140
+ opacity: 0.8,
141
+ visibility: false,
236
142
  },
237
- true,
238
- );
239
- expect(hash).toBeTypeOf("string");
240
- expect(hash).toEqual(
241
- getLayerHash(
242
- {
243
- ...SAMPLE_LAYER1,
244
- extras: {
245
- func: () => 456,
246
- canvas: document.createElement("div"),
247
- },
248
- },
249
- true,
250
- ),
251
- );
252
- expect(hash).not.toEqual(
253
- getLayerHash(
254
- {
255
- ...SAMPLE_LAYER1,
256
- extras: {},
257
- },
258
- true,
259
- ),
260
- );
261
- });
262
- it("does not take into account properties order", () => {
263
- expect(
264
- getLayerHash(
265
- {
266
- type: "wms",
267
- url: "http://abc.org/wms",
268
- name: "myLayer",
269
- extras: {
270
- array: [1, 2, 3],
271
- object: {},
272
- },
273
- },
274
- true,
275
- ),
276
- ).toEqual(
277
- getLayerHash(
278
- {
279
- extras: {
280
- array: [1, 2, 3],
281
- object: {},
282
- },
283
- url: "http://abc.org/wms",
284
- type: "wms",
285
- name: "myLayer",
286
- },
287
- true,
288
- ),
289
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);
290
154
  });
291
- });
292
-
293
- describe("getLayerPosition", () => {
294
- it("returns the index of the layer in the context", () => {
155
+ it("changes the context ref even if the layer is not found (the layers array is untouched)", () => {
295
156
  const context: MapContext = {
296
157
  ...SAMPLE_CONTEXT,
297
158
  layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
298
159
  };
299
- expect(getLayerPosition(context, SAMPLE_LAYER1)).toBe(0);
300
- expect(getLayerPosition(context, SAMPLE_LAYER2)).toBe(1);
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);
301
165
  });
302
166
  });
303
167
  });
@@ -1,51 +1,120 @@
1
- import { MapContext, MapContextLayer } from "../model";
2
-
3
- export function getLayerHash(
4
- layer: MapContextLayer,
5
- includeExtras = false,
6
- ): string {
7
- function getHash(input: unknown): string {
8
- if (input instanceof Object) {
9
- const obj: Record<string, string> = {};
10
- const keys = Object.keys(input).sort();
11
- for (const key of keys) {
12
- if (!includeExtras && key === "extras") continue;
13
- obj[key] = getHash(input[key as keyof typeof input]);
14
- }
15
- const hash = JSON.stringify(obj)
16
- .split("")
17
- .reduce((prev, curr) => (prev << 5) - prev + curr.charCodeAt(0), 0);
18
- return (hash >>> 0).toString();
19
- } else {
20
- return JSON.stringify(input);
21
- }
1
+ import { MapContext, MapContextLayer } from "../model/index.js";
2
+ import { isLayerSame, updateLayer } from "./map-context-layer.js";
3
+
4
+ export function getLayerPosition(
5
+ context: MapContext,
6
+ layerModel: MapContextLayer,
7
+ ): number {
8
+ return context.layers.findIndex((l) => isLayerSame(layerModel, l));
9
+ }
10
+
11
+ /**
12
+ * Adds a layer to the context at a specific position or at the end if no position is specified.
13
+ *
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.
18
+ */
19
+
20
+ export function addLayerToContext(
21
+ context: MapContext,
22
+ layerModel: MapContextLayer,
23
+ position?: number,
24
+ ): MapContext {
25
+ const newContext = { ...context, layers: [...context.layers] };
26
+ if (position !== undefined) {
27
+ newContext.layers.splice(position, 0, layerModel);
28
+ } else {
29
+ newContext.layers.push(layerModel);
22
30
  }
23
- return getHash(layer);
31
+ return newContext;
24
32
  }
25
33
 
26
- export function isLayerSame(
27
- layerA: MapContextLayer,
28
- layerB: MapContextLayer,
29
- ): boolean {
30
- if ("id" in layerA && "id" in layerB) {
31
- return layerA.id == layerB.id;
34
+ /**
35
+ * Removes a layer from the context.
36
+ *
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.
40
+ */
41
+
42
+ export function removeLayerFromContext(
43
+ context: MapContext,
44
+ layerModel: MapContextLayer,
45
+ ): MapContext {
46
+ const newContext = { ...context, layers: [...context.layers] };
47
+ const position = getLayerPosition(context, layerModel);
48
+ if (position >= 0) {
49
+ newContext.layers.splice(position, 1);
32
50
  }
33
- return getLayerHash(layerA) === getLayerHash(layerB);
51
+ return newContext;
34
52
  }
35
53
 
36
- export function isLayerSameAndUnchanged(
37
- layerA: MapContextLayer,
38
- layerB: MapContextLayer,
39
- ): boolean {
40
- if ("id" in layerA && "id" in layerB) {
41
- return layerA.id == layerB.id && layerA.version == layerB.version;
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 replacement The new layer that will replace the old one.
60
+ * @returns The new map context with the replaced layer.
61
+ */
62
+
63
+ export function replaceLayerInContext(
64
+ context: MapContext,
65
+ layerModel: MapContextLayer,
66
+ replacement: MapContextLayer,
67
+ ): MapContext {
68
+ const newContext = { ...context, layers: [...context.layers] };
69
+ const position = getLayerPosition(context, layerModel);
70
+ if (position >= 0) {
71
+ newContext.layers.splice(position, 1, replacement);
42
72
  }
43
- return getLayerHash(layerA, true) === getLayerHash(layerB, true);
73
+ return newContext;
44
74
  }
45
75
 
46
- export function getLayerPosition(
76
+ /**
77
+ * Updates an existing layer in the context by applying partial changes.
78
+ *
79
+ * Note: setting a property to `undefined` in the partial layer updates will remove that
80
+ * property from the existing layer.
81
+ *
82
+ * @param context The current map context.
83
+ * @param layerModel The layer to be updated.
84
+ * @param layerUpdates A partial layer object containing the properties to update on the existing layer.
85
+ * @returns The new map context with the updated layer.
86
+ */
87
+
88
+ export function updateLayerInContext(
47
89
  context: MapContext,
48
90
  layerModel: MapContextLayer,
49
- ): number {
50
- return context.layers.findIndex((l) => isLayerSame(layerModel, l));
91
+ layerUpdates: Partial<MapContextLayer>,
92
+ ): MapContext {
93
+ const position = getLayerPosition(context, layerModel);
94
+ if (position >= 0) {
95
+ const existing = context.layers[position];
96
+ const updated = updateLayer(existing, layerUpdates);
97
+ return replaceLayerInContext(context, layerModel, updated);
98
+ }
99
+ // we're building a new context so that the reference is changed anyway; this is done to be
100
+ // consistent with other utilities that always change the context reference even if the layer wasn't found
101
+ return { ...context };
102
+ }
103
+
104
+ /**
105
+ * Changes the position of a layer in the context.
106
+ *
107
+ * @param context The current map context.
108
+ * @param layerModel The layer whose position is to be changed.
109
+ * @param position The new position for the layer.
110
+ * @returns The new map context with the layer moved to the new position.
111
+ */
112
+
113
+ export function changeLayerPositionInContext(
114
+ context: MapContext,
115
+ layerModel: MapContextLayer,
116
+ position: number,
117
+ ): MapContext {
118
+ const newContext = removeLayerFromContext(context, layerModel);
119
+ return addLayerToContext(newContext, layerModel, position);
51
120
  }
@@ -0,0 +1,71 @@
1
+ import type { FlatStyleLike } from "ol/style/flat.js";
2
+
3
+ const color = "rgb(0, 0, 255)";
4
+ const fillColor = "rgba(0, 0, 255, 0.25)";
5
+ export const defaultStyle: FlatStyleLike = [
6
+ {
7
+ filter: ["==", ["geometry-type"], "LineString"],
8
+ style: [
9
+ {
10
+ "stroke-color": "white",
11
+ "stroke-width": 6,
12
+ },
13
+ {
14
+ "stroke-color": color,
15
+ "stroke-width": 2,
16
+ },
17
+ ],
18
+ },
19
+ {
20
+ filter: ["==", ["geometry-type"], "Polygon"],
21
+ style: {
22
+ "stroke-color": "white",
23
+ "stroke-width": 2,
24
+ "fill-color": fillColor,
25
+ },
26
+ },
27
+ {
28
+ filter: ["==", ["geometry-type"], "Point"],
29
+ style: {
30
+ "circle-fill-color": color,
31
+ "circle-radius": 7,
32
+ "circle-stroke-color": "white",
33
+ "circle-stroke-width": 2,
34
+ },
35
+ },
36
+ ];
37
+
38
+ const hlColor = "rgb(0, 0, 255)";
39
+ const hlFillColor = "rgba(0, 0, 255, 0.25)";
40
+ export const defaultHighlightStyle: FlatStyleLike = [
41
+ {
42
+ filter: ["==", ["geometry-type"], "LineString"],
43
+ style: [
44
+ {
45
+ "stroke-color": "white",
46
+ "stroke-width": 8,
47
+ },
48
+ {
49
+ "stroke-color": hlColor,
50
+ "stroke-width": 3,
51
+ },
52
+ ],
53
+ },
54
+ {
55
+ filter: ["==", ["geometry-type"], "Polygon"],
56
+ style: {
57
+ "stroke-color": "white",
58
+ "stroke-width": 3,
59
+ "fill-color": hlFillColor,
60
+ },
61
+ },
62
+ {
63
+ filter: ["==", ["geometry-type"], "Point"],
64
+ style: {
65
+ "circle-fill-color": hlColor,
66
+ "circle-radius": 8,
67
+ "circle-stroke-color": "white",
68
+ "circle-stroke-width": 3,
69
+ },
70
+ },
71
+ ];
@@ -1,4 +1,4 @@
1
- import { removeSearchParams } from "./url";
1
+ import { removeSearchParams } from "./url.js";
2
2
 
3
3
  describe("URL utils", () => {
4
4
  describe("removeSearchParams", () => {