@geospatial-sdk/openlayers 0.0.5-dev.51 → 0.0.5-dev.53

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 (35) hide show
  1. package/dist/map/feature-hover.d.ts +4 -4
  2. package/dist/map/feature-hover.d.ts.map +1 -1
  3. package/dist/map/feature-hover.js +28 -7
  4. package/dist/map/feature-selection.d.ts +8 -0
  5. package/dist/map/feature-selection.d.ts.map +1 -0
  6. package/dist/map/feature-selection.js +76 -0
  7. package/dist/map/get-features.d.ts +10 -9
  8. package/dist/map/get-features.d.ts.map +1 -1
  9. package/dist/map/get-features.js +60 -31
  10. package/dist/map/layer-update.d.ts.map +1 -1
  11. package/dist/map/layer-update.js +8 -0
  12. package/dist/map/listen.d.ts +4 -0
  13. package/dist/map/listen.d.ts.map +1 -0
  14. package/dist/map/listen.js +83 -0
  15. package/dist/map/register-events.d.ts +1 -1
  16. package/dist/map/register-events.d.ts.map +1 -1
  17. package/dist/map/register-events.js +7 -2
  18. package/dist/map/resolved-map-state.d.ts +8 -0
  19. package/dist/map/resolved-map-state.d.ts.map +1 -0
  20. package/dist/map/resolved-map-state.js +27 -0
  21. package/dist/map/styles.d.ts +16 -0
  22. package/dist/map/styles.d.ts.map +1 -0
  23. package/dist/map/styles.js +77 -0
  24. package/dist/resolved-state/resolved-map-state.d.ts +2 -0
  25. package/dist/resolved-state/resolved-map-state.d.ts.map +1 -0
  26. package/dist/resolved-state/resolved-map-state.js +1 -0
  27. package/lib/map/feature-hover.ts +52 -17
  28. package/lib/map/get-features.test.ts +32 -20
  29. package/lib/map/get-features.ts +85 -48
  30. package/lib/map/handle-errors.test.ts +4 -4
  31. package/lib/map/layer-update.test.ts +6 -1
  32. package/lib/map/layer-update.ts +16 -1
  33. package/lib/map/register-events.test.ts +60 -64
  34. package/lib/map/register-events.ts +13 -5
  35. package/package.json +3 -3
@@ -1,24 +1,22 @@
1
1
  import { GEOSPATIAL_SDK_PREFIX } from "./constants.js";
2
- import type Map from "ol/Map.js";
2
+ import type OlMap from "ol/Map.js";
3
3
  import VectorLayer from "ol/layer/Vector.js";
4
4
  import VectorSource from "ol/source/Vector.js";
5
5
  import {
6
6
  defaultHighlightStyle,
7
7
  FeaturesHoverEventType,
8
8
  } from "@geospatial-sdk/core";
9
- import BaseEvent from "ol/events/Event.js";
9
+ import type BaseEvent from "ol/events/Event.js";
10
10
  import { MapBrowserEvent } from "ol";
11
- import GeoJSON from "ol/format/GeoJSON.js";
12
- import Feature from "ol/Feature.js";
13
- import BaseLayer from "ol/layer/Base.js";
11
+ import OlFeature from "ol/Feature.js";
12
+ import type BaseLayer from "ol/layer/Base.js";
14
13
  import { unByKey } from "ol/Observable.js";
15
-
16
- const GEOJSON = new GeoJSON();
14
+ import { readFeaturesAtPixel } from "./get-features.js";
17
15
 
18
16
  const hoverLayerKey = `${GEOSPATIAL_SDK_PREFIX}hover-layer`;
19
17
  const unsubscribeKey = `${GEOSPATIAL_SDK_PREFIX}hover-unsub`;
20
18
 
21
- export function initHoverLayer(map: Map) {
19
+ export function initHoverLayer(map: OlMap) {
22
20
  if (map.get(hoverLayerKey)) {
23
21
  clearHoverLayer(map);
24
22
  }
@@ -30,6 +28,10 @@ export function initHoverLayer(map: Map) {
30
28
  useSpatialIndex: false,
31
29
  }),
32
30
  style: defaultHighlightStyle,
31
+ properties: {
32
+ [`${GEOSPATIAL_SDK_PREFIX}enable-hover`]: false,
33
+ [`${GEOSPATIAL_SDK_PREFIX}disable-click`]: true,
34
+ },
33
35
  });
34
36
  map.set(hoverLayerKey, hoverLayer);
35
37
  hoverLayer.setMap(map);
@@ -38,7 +40,7 @@ export function initHoverLayer(map: Map) {
38
40
  const originalCursorStyle = map.getTargetElement()?.style.cursor ?? "";
39
41
 
40
42
  const layerFilter = (layer: BaseLayer) =>
41
- layer !== hoverLayer && layer.get(`${GEOSPATIAL_SDK_PREFIX}enable-hover`);
43
+ layer.get(`${GEOSPATIAL_SDK_PREFIX}enable-hover`);
42
44
 
43
45
  const unKey = map.on(
44
46
  "pointermove",
@@ -65,17 +67,50 @@ export function initHoverLayer(map: Map) {
65
67
  }
66
68
 
67
69
  // add hovered feature to the layer
68
- const hovered = map.getFeaturesAtPixel(event.pixel, {
69
- layerFilter,
70
- }) as Feature[];
71
- hoveredSource.addFeature(hovered[0]);
70
+ const hoveredFeatureResult: {
71
+ feature: OlFeature;
72
+ layer: BaseLayer;
73
+ }[] = [];
74
+ map.forEachFeatureAtPixel(
75
+ event.pixel,
76
+ (feature, layer) => {
77
+ if (feature instanceof OlFeature) {
78
+ hoveredFeatureResult.push({ feature, layer });
79
+ return true;
80
+ }
81
+ },
82
+ {
83
+ layerFilter,
84
+ },
85
+ );
86
+ if (hoveredFeatureResult.length === 0) {
87
+ return;
88
+ }
89
+
90
+ const { feature: firstFeature, layer: sourceLayer } =
91
+ hoveredFeatureResult[0];
92
+
93
+ // Get the hoverStyle from the source layer, fallback to defaultHighlightStyle
94
+ const hoverStyle =
95
+ sourceLayer.get(`${GEOSPATIAL_SDK_PREFIX}hover-style`) ??
96
+ defaultHighlightStyle;
97
+
98
+ // Apply the hover style to the layer (FlatStyleLike works on layers, not features)
99
+ hoverLayer.setStyle(hoverStyle);
100
+ hoveredSource.addFeature(firstFeature);
72
101
 
73
102
  // dispatch event if subscribed to
74
103
  if (map.get(FeaturesHoverEventType)) {
75
- const { features } = GEOJSON.writeFeaturesObject(hovered);
104
+ const featuresByLayer = await readFeaturesAtPixel(
105
+ map,
106
+ event,
107
+ layerFilter,
108
+ );
109
+ const features = Array.from(featuresByLayer.values()).flat();
76
110
  map.dispatchEvent({
77
111
  type: FeaturesHoverEventType,
78
- features: features ?? [],
112
+ features,
113
+ featuresByLayer,
79
114
  } as unknown as BaseEvent);
80
115
  }
81
116
  },
@@ -83,11 +118,11 @@ export function initHoverLayer(map: Map) {
83
118
  map.set(unsubscribeKey, unKey);
84
119
  }
85
120
 
86
- export function getHoverLayer(map: Map): VectorLayer<VectorSource> {
121
+ export function getHoverLayer(map: OlMap): VectorLayer<VectorSource> {
87
122
  return map.get(hoverLayerKey) as VectorLayer<VectorSource>;
88
123
  }
89
124
 
90
- export function clearHoverLayer(map: Map) {
125
+ export function clearHoverLayer(map: OlMap) {
91
126
  const hoverLayer = getHoverLayer(map);
92
127
  hoverLayer.setMap(null);
93
128
  hoverLayer.dispose();
@@ -3,7 +3,7 @@ import {
3
3
  getFeaturesFromWmsSources,
4
4
  getGFIUrl,
5
5
  } from "./get-features.js";
6
- import Map from "ol/Map.js";
6
+ import OlMap from "ol/Map.js";
7
7
  import TileWMS from "ol/source/TileWMS.js";
8
8
  import TileLayer from "ol/layer/Tile.js";
9
9
  import OlFeature from "ol/Feature.js";
@@ -12,6 +12,7 @@ import VectorLayer from "ol/layer/Vector.js";
12
12
  import VectorSource from "ol/source/Vector.js";
13
13
  import View from "ol/View.js";
14
14
  import { Collection, Object as BaseObject } from "ol";
15
+ import { toLonLat } from "ol/proj.js";
15
16
 
16
17
  const gfiResult = {
17
18
  type: "Feature",
@@ -30,7 +31,7 @@ function createWmsSource() {
30
31
  },
31
32
  });
32
33
  }
33
- function createMap(): Map {
34
+ function createMap(): OlMap {
34
35
  const wmsLayer = new TileLayer({
35
36
  source: createWmsSource(),
36
37
  });
@@ -47,23 +48,27 @@ function createMap(): Map {
47
48
  resolution: 1,
48
49
  center: [0, 0],
49
50
  });
50
- const map = new BaseObject() as Map;
51
+ const map = new BaseObject() as OlMap;
51
52
  Object.defineProperties(map, {
52
53
  getView: { value: vi.fn(() => view) },
53
54
  getLayers: { value: vi.fn(() => new Collection([wmsLayer, vectorLayer])) },
54
55
  getEventPixel: { value: vi.fn(() => [10, 10]) },
55
56
  getCoordinateFromPixel: { value: vi.fn(() => [123, 123]) },
56
- getFeaturesAtPixel: { value: vi.fn(() => [feature]) },
57
+ forEachFeatureAtPixel: {
58
+ value: vi.fn((pixel, callback) => {
59
+ callback(feature, vectorLayer);
60
+ }),
61
+ },
57
62
  getSize: { value: vi.fn(() => [800, 600]) },
58
63
  });
59
64
  return map;
60
65
  }
61
66
 
62
67
  describe("get features utils", () => {
63
- let map: Map;
68
+ let map: OlMap;
64
69
  beforeEach(() => {
65
70
  map = createMap();
66
- vi.spyOn(global, "fetch").mockImplementation(() =>
71
+ vi.spyOn(globalThis, "fetch").mockImplementation(() =>
67
72
  Promise.resolve({
68
73
  ok: true,
69
74
  json: () => Promise.resolve({ features: [gfiResult] }),
@@ -73,18 +78,25 @@ describe("get features utils", () => {
73
78
  });
74
79
 
75
80
  describe("getFeaturesFromVectorSources", () => {
76
- it("returns an array of features", () => {
77
- const features = getFeaturesFromVectorSources(map, [0, 0]);
78
- expect(features).toEqual([
79
- {
80
- geometry: {
81
- coordinates: [100, 200],
82
- type: "Point",
83
- },
84
- properties: null,
85
- type: "Feature",
86
- },
87
- ]);
81
+ it("returns a map of features by layer index", () => {
82
+ const featuresByLayerIndex = getFeaturesFromVectorSources(map, [0, 0]);
83
+ expect(featuresByLayerIndex).toEqual(
84
+ new Map([
85
+ [
86
+ 1,
87
+ [
88
+ {
89
+ geometry: {
90
+ coordinates: toLonLat([100, 200]),
91
+ type: "Point",
92
+ },
93
+ properties: null,
94
+ type: "Feature",
95
+ },
96
+ ],
97
+ ],
98
+ ]),
99
+ );
88
100
  });
89
101
  });
90
102
  describe("getGFIUrl", () => {
@@ -102,8 +114,8 @@ describe("get features utils", () => {
102
114
  });
103
115
  describe("getFeaturesFromWmsSources", () => {
104
116
  it("queries the WMS sources", async () => {
105
- const features = await getFeaturesFromWmsSources(map, [0, 0]);
106
- expect(features).toEqual([gfiResult]);
117
+ const featuresByLayerIndex = await getFeaturesFromWmsSources(map, [0, 0]);
118
+ expect(featuresByLayerIndex).toEqual(new Map([[0, [gfiResult]]]));
107
119
  });
108
120
  });
109
121
  });
@@ -1,32 +1,52 @@
1
- import GeoJSON from "ol/format/GeoJSON.js";
2
- import Map from "ol/Map.js";
3
- import { Pixel } from "ol/pixel.js";
1
+ import type { FeaturesByLayerIndex } from "@geospatial-sdk/core";
4
2
  import type { Feature, FeatureCollection } from "geojson";
5
- import OlFeature from "ol/Feature.js";
6
- import TileWMS from "ol/source/TileWMS.js";
7
- import ImageWMS from "ol/source/ImageWMS.js";
3
+ import throttle from "lodash.throttle";
8
4
  import { Coordinate } from "ol/coordinate.js";
5
+ import OlFeature from "ol/Feature.js";
6
+ import GeoJSON from "ol/format/GeoJSON.js";
9
7
  import Layer from "ol/layer/Layer.js";
10
- import throttle from "lodash.throttle";
11
- import { MapBrowserEvent } from "ol";
8
+ import OlMap from "ol/Map.js";
9
+ import type MapBrowserEvent from "ol/MapBrowserEvent.js";
10
+ import { Pixel } from "ol/pixel.js";
11
+ import ImageWMS from "ol/source/ImageWMS.js";
12
+ import TileWMS from "ol/source/TileWMS.js";
12
13
 
13
14
  const GEOJSON = new GeoJSON();
14
15
 
15
16
  export function getFeaturesFromVectorSources(
16
- olMap: Map,
17
+ olMap: OlMap,
17
18
  pixel: Pixel,
18
- ): Feature[] {
19
- const olFeatures = olMap.getFeaturesAtPixel(pixel);
20
- const { features } = GEOJSON.writeFeaturesObject(olFeatures as OlFeature[]);
21
- if (!features) {
22
- return [];
23
- }
24
- return features;
19
+ layerFilter?: (layer: Layer) => boolean,
20
+ ): FeaturesByLayerIndex {
21
+ const result = new Map<number, Feature[]>();
22
+ const layerArray = olMap.getLayers().getArray();
23
+ olMap.forEachFeatureAtPixel(
24
+ pixel,
25
+ (feature, layer) => {
26
+ // can happen for unmanaged layer (i.e. hover layer)
27
+ if (layer === null) {
28
+ return null;
29
+ }
30
+ const layerIndex = layerArray.indexOf(layer);
31
+ if (!result.has(layerIndex)) {
32
+ result.set(layerIndex, []);
33
+ }
34
+ result.get(layerIndex)!.push(
35
+ GEOJSON.writeFeatureObject(feature as OlFeature, {
36
+ featureProjection: olMap.getView().getProjection(),
37
+ dataProjection: "EPSG:4326",
38
+ }),
39
+ );
40
+ return null;
41
+ },
42
+ { layerFilter },
43
+ );
44
+ return result;
25
45
  }
26
46
 
27
47
  export function getGFIUrl(
28
48
  source: TileWMS | ImageWMS,
29
- map: Map,
49
+ map: OlMap,
30
50
  coordinate: Coordinate,
31
51
  ): string | null {
32
52
  const view = map.getView();
@@ -41,36 +61,48 @@ export function getGFIUrl(
41
61
  );
42
62
  }
43
63
 
44
- export function getFeaturesFromWmsSources(
45
- olMap: Map,
64
+ export async function getFeaturesFromWmsSources(
65
+ olMap: OlMap,
46
66
  coordinate: Coordinate,
47
- ): Promise<Feature[]> {
48
- const wmsSources: (ImageWMS | TileWMS)[] = olMap
49
- .getLayers()
50
- .getArray()
51
- .filter(
52
- (layer): layer is Layer<ImageWMS | TileWMS> =>
53
- layer instanceof Layer &&
54
- (layer.getSource() instanceof TileWMS ||
55
- layer.getSource() instanceof ImageWMS),
56
- )
57
- .map((layer) => layer.getSource()!);
67
+ layerFilter?: (layer: Layer) => boolean,
68
+ ): Promise<FeaturesByLayerIndex> {
69
+ const result = new Map<number, Feature[]>();
70
+ const layerArray = olMap.getLayers().getArray();
58
71
 
59
- if (!wmsSources.length) {
60
- return Promise.resolve([]);
72
+ const hasWms = layerArray.some((layer) => {
73
+ const source = layer instanceof Layer ? layer.getSource() : null;
74
+ return source instanceof TileWMS || source instanceof ImageWMS;
75
+ });
76
+ if (!hasWms) {
77
+ return result;
61
78
  }
62
79
 
63
- const gfiUrls = wmsSources.reduce((urls, source) => {
80
+ const gfiPromises: (Promise<Feature[]> | null)[] = layerArray.map((layer) => {
81
+ if (!(layer instanceof Layer)) {
82
+ return null;
83
+ }
84
+ if (layerFilter && !layerFilter(layer)) {
85
+ return null;
86
+ }
87
+ const source = layer.getSource();
88
+ if (!(source instanceof TileWMS) && !(source instanceof ImageWMS)) {
89
+ return null;
90
+ }
64
91
  const gfiUrl = getGFIUrl(source, olMap, coordinate);
65
- return gfiUrl ? [...urls, gfiUrl] : urls;
66
- }, [] as string[]);
67
- return Promise.all(
68
- gfiUrls.map((url) =>
69
- fetch(url)
70
- .then((response) => response.json())
71
- .then((collection: FeatureCollection) => collection.features),
72
- ),
73
- ).then((features) => features.flat());
92
+ return gfiUrl
93
+ ? fetch(gfiUrl)
94
+ .then((response) => response.json())
95
+ .then((collection: FeatureCollection) => collection.features)
96
+ : null;
97
+ });
98
+
99
+ const responses = await Promise.all(gfiPromises);
100
+ responses.forEach((features, index) => {
101
+ if (features !== null && features.length > 0) {
102
+ result.set(index, features);
103
+ }
104
+ });
105
+ return result;
74
106
  }
75
107
 
76
108
  const getFeaturesFromWmsSourcesThrottled = throttle(
@@ -79,11 +111,16 @@ const getFeaturesFromWmsSourcesThrottled = throttle(
79
111
  );
80
112
 
81
113
  export async function readFeaturesAtPixel(
82
- map: Map,
114
+ map: OlMap,
83
115
  event: MapBrowserEvent<PointerEvent>,
84
- ) {
85
- return [
86
- ...getFeaturesFromVectorSources(map, event.pixel),
87
- ...(await getFeaturesFromWmsSourcesThrottled(map, event.coordinate)),
88
- ];
116
+ layerFilter?: (layer: Layer) => boolean,
117
+ ): Promise<FeaturesByLayerIndex> {
118
+ return new Map([
119
+ ...getFeaturesFromVectorSources(map, event.pixel, layerFilter),
120
+ ...(await getFeaturesFromWmsSourcesThrottled(
121
+ map,
122
+ event.coordinate,
123
+ layerFilter,
124
+ )),
125
+ ]);
89
126
  }
@@ -9,7 +9,7 @@ import TileLayer from "ol/layer/Tile.js";
9
9
  import VectorLayer from "ol/layer/Vector.js";
10
10
  import { EndpointError } from "@camptocamp/ogc-client";
11
11
 
12
- global.URL.createObjectURL = vi.fn(() => "blob:http://example.com/blob");
12
+ globalThis.URL.createObjectURL = vi.fn(() => "blob:http://example.com/blob");
13
13
 
14
14
  const mockBlob = new Blob();
15
15
  const RESPONSE_OK = {
@@ -19,10 +19,10 @@ const RESPONSE_OK = {
19
19
  const RESPONSE_ERROR = {
20
20
  status: 404,
21
21
  };
22
- global.fetch = vi.fn().mockImplementation((url: string) => {
22
+ globalThis.fetch = vi.fn().mockImplementation((url: string) => {
23
23
  return url.includes("error")
24
- ? Promise.reject(RESPONSE_ERROR as Response)
25
- : Promise.resolve(RESPONSE_OK as Response);
24
+ ? Promise.reject(RESPONSE_ERROR)
25
+ : Promise.resolve(RESPONSE_OK);
26
26
  });
27
27
 
28
28
  describe("handle-errors", () => {
@@ -116,7 +116,7 @@ describe("Layer update utils", () => {
116
116
  expect(olLayer.set).toHaveBeenCalledWith("label", "Test Layer");
117
117
  });
118
118
 
119
- it("applies properties specific to vector layers without recreating them", async () => {
119
+ it("enable interaction-related props without recreating them", async () => {
120
120
  // mocking a vector layer
121
121
  (olLayer as VectorLayer).setStyle = vi.fn();
122
122
 
@@ -126,6 +126,7 @@ describe("Layer update utils", () => {
126
126
  "circle-fill-color": "blue",
127
127
  },
128
128
  enableHover: true,
129
+ disableClick: true,
129
130
  };
130
131
  const prevLayerModel = SAMPLE_LAYER3;
131
132
  updateLayerProperties(layerModel, olLayer, prevLayerModel);
@@ -136,6 +137,10 @@ describe("Layer update utils", () => {
136
137
  "--geospatial-sdk-enable-hover",
137
138
  true,
138
139
  );
140
+ expect(olLayer.set).toHaveBeenCalledWith(
141
+ "--geospatial-sdk-disable-click",
142
+ true,
143
+ );
139
144
  });
140
145
  });
141
146
  });
@@ -6,6 +6,7 @@ import {
6
6
  import Layer from "ol/layer/Layer.js";
7
7
  import { GEOSPATIAL_SDK_PREFIX } from "./constants.js";
8
8
  import VectorLayer from "ol/layer/Vector.js";
9
+ import type VectorSource from "ol/source/Vector.js";
9
10
 
10
11
  const UPDATABLE_PROPERTIES: (
11
12
  | keyof MapContextBaseLayer
@@ -18,7 +19,9 @@ const UPDATABLE_PROPERTIES: (
18
19
  "extras",
19
20
  "version",
20
21
  "enableHover",
22
+ "disableClick",
21
23
  "style",
24
+ "hoverStyle",
22
25
  // TODO (when available) "zIndex"
23
26
  ];
24
27
 
@@ -85,11 +88,23 @@ export function updateLayerProperties(
85
88
  (layerModel as MapContextLayerVector).enableHover,
86
89
  );
87
90
  }
91
+ if (shouldApplyProperty("hoverStyle" as keyof MapContextLayer)) {
92
+ olLayer.set(
93
+ `${GEOSPATIAL_SDK_PREFIX}hover-style`,
94
+ (layerModel as MapContextLayerVector).hoverStyle,
95
+ );
96
+ }
97
+ if (shouldApplyProperty("disableClick" as keyof MapContextLayer)) {
98
+ olLayer.set(
99
+ `${GEOSPATIAL_SDK_PREFIX}disable-click`,
100
+ layerModel.disableClick,
101
+ );
102
+ }
88
103
  if (
89
104
  shouldApplyProperty("style" as keyof MapContextLayer) &&
90
105
  "setStyle" in olLayer
91
106
  ) {
92
- (olLayer as VectorLayer).setStyle(
107
+ (olLayer as VectorLayer<VectorSource>).setStyle(
93
108
  (layerModel as MapContextLayerVector).style,
94
109
  );
95
110
  }
@@ -1,89 +1,104 @@
1
- import Map from "ol/Map.js";
1
+ import OlMap from "ol/Map.js";
2
2
  import { Mock } from "vitest";
3
3
  import { listen } from "./register-events.js";
4
4
  import { MapBrowserEvent, Object as BaseObject } from "ol";
5
5
  import View from "ol/View.js";
6
6
  import { toLonLat } from "ol/proj.js";
7
- import Point from "ol/geom/Point.js";
8
- import OlFeature from "ol/Feature.js";
9
7
  import { FeaturesHoverEventType } from "@geospatial-sdk/core";
10
8
  import BaseEvent from "ol/events/Event.js";
11
9
 
12
10
  vi.mock("./get-features.js", () => ({
13
11
  readFeaturesAtPixel() {
14
- return [
15
- {
16
- geometry: {
17
- coordinates: [100, 200],
18
- type: "Point",
19
- },
20
- properties: null,
21
- type: "Feature",
22
- },
23
- {
24
- geometry: null,
25
- properties: {
26
- density: 123,
27
- },
28
- type: "Feature",
29
- },
30
- ];
12
+ return Promise.resolve(
13
+ new Map([
14
+ [
15
+ 0,
16
+ [
17
+ {
18
+ geometry: {
19
+ coordinates: [100, 200],
20
+ type: "Point",
21
+ },
22
+ properties: null,
23
+ type: "Feature",
24
+ },
25
+ ],
26
+ ],
27
+ [
28
+ 1,
29
+ [
30
+ {
31
+ geometry: null,
32
+ properties: {
33
+ density: 123,
34
+ },
35
+ type: "Feature",
36
+ },
37
+ ],
38
+ ],
39
+ ]),
40
+ );
31
41
  },
32
42
  }));
33
43
 
44
+ const featureA = {
45
+ geometry: {
46
+ coordinates: [100, 200],
47
+ type: "Point",
48
+ },
49
+ properties: null,
50
+ type: "Feature",
51
+ };
52
+ const featureB = {
53
+ geometry: null,
54
+ properties: {
55
+ density: 123,
56
+ },
57
+ type: "Feature",
58
+ };
59
+
34
60
  const EXPECTED_MAP_EXTENT_EPSG4326 = [
35
61
  -0.0035932611364780857, -0.0026949458513598756, 0.0035932611364780857,
36
62
  0.0026949458513740865,
37
63
  ];
38
64
 
39
- function createMap(): Map {
40
- const feature = new OlFeature({
41
- geometry: new Point([100, 200]),
42
- });
65
+ function createMap(): OlMap {
43
66
  const view = new View({
44
67
  projection: "EPSG:3857",
45
68
  resolution: 1,
46
69
  center: [0, 0],
47
70
  });
48
- const map = new BaseObject() as Map;
71
+ const map = new BaseObject() as OlMap;
49
72
  Object.defineProperties(map, {
50
73
  getView: { value: vi.fn(() => view) },
51
74
  getEventPixel: { value: vi.fn(() => [10, 10]) },
52
75
  getCoordinateFromPixel: { value: vi.fn(() => [123, 123]) },
53
- getFeaturesAtPixel: { value: vi.fn(() => [feature]) },
54
76
  getSize: { value: vi.fn(() => [800, 600]) },
55
77
  });
56
78
  // simulate hover feature initialization
57
79
  map.on("pointermove", () => {
58
80
  map.dispatchEvent({
59
81
  type: FeaturesHoverEventType,
60
- features: [
61
- {
62
- geometry: null,
63
- properties: {
64
- density: 123,
65
- },
66
- type: "Feature",
67
- },
68
- ],
82
+ features: [featureB],
83
+ featuresByLayer: new Map([[0, [featureB]]]),
69
84
  } as unknown as BaseEvent);
70
85
  });
71
86
  return map;
72
87
  }
73
- function createMapEvent(map: Map, type: string) {
88
+ function createMapEvent(map: OlMap, type: string) {
74
89
  return new MapBrowserEvent(
75
90
  type,
76
91
  map,
77
92
  new MouseEvent(type, {
78
93
  clientX: 10,
79
94
  clientY: 10,
80
- }),
95
+ }) as PointerEvent,
81
96
  false,
82
97
  );
83
98
  }
84
99
 
85
100
  describe("event registration", () => {
86
- let map: Map;
101
+ let map: OlMap;
87
102
  beforeEach(() => {
88
103
  map = createMap();
89
104
  vi.useFakeTimers();
@@ -99,15 +114,8 @@ describe("event registration", () => {
99
114
  it("registers the event on the map", () => {
100
115
  expect(callback).toHaveBeenCalledWith({
101
116
  type: "features-hover",
102
- features: [
103
- {
104
- geometry: null,
105
- properties: {
106
- density: 123,
107
- },
108
- type: "Feature",
109
- },
110
- ],
117
+ features: [featureB],
118
+ featuresByLayer: new Map([[0, [featureB]]]),
111
119
  target: expect.anything(),
112
120
  });
113
121
  });
@@ -123,23 +131,11 @@ describe("event registration", () => {
123
131
  it("registers the event on the map", () => {
124
132
  expect(callback).toHaveBeenCalledWith({
125
133
  type: "features-click",
126
- features: [
127
- {
128
- geometry: {
129
- coordinates: [100, 200],
130
- type: "Point",
131
- },
132
- properties: null,
133
- type: "Feature",
134
- },
135
- {
136
- geometry: null,
137
- properties: {
138
- density: 123,
139
- },
140
- type: "Feature",
141
- },
142
- ],
134
+ features: [featureA, featureB],
135
+ featuresByLayer: new Map([
136
+ [0, [featureA]],
137
+ [1, [featureB]],
138
+ ]),
143
139
  target: expect.anything(),
144
140
  });
145
141
  });