@open-pioneer/map 1.3.0-dev.20260310142705 → 1.3.0-dev.20260408130821
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/CHANGELOG.md +6 -3
- package/index.d.ts +1 -1
- package/model/Highlights.d.ts +1 -5
- package/model/Highlights.js +19 -19
- package/model/Highlights.js.map +1 -1
- package/model/MapModel.d.ts +10 -0
- package/model/MapModel.js +11 -1
- package/model/MapModel.js.map +1 -1
- package/model/Overlays.d.ts +115 -37
- package/model/Overlays.js +136 -53
- package/model/Overlays.js.map +1 -1
- package/package.json +8 -8
- package/ui/MapContainer.js +46 -10
- package/ui/MapContainer.js.map +1 -1
package/model/Overlays.d.ts
CHANGED
|
@@ -12,63 +12,73 @@ export declare const UNREGISTER_OVERLAY: unique symbol;
|
|
|
12
12
|
* @group Map Model
|
|
13
13
|
*/
|
|
14
14
|
export declare class Overlays {
|
|
15
|
-
private
|
|
16
|
-
private overlays;
|
|
15
|
+
#private;
|
|
17
16
|
constructor(map: MapModel);
|
|
18
17
|
[REGISTER_OVERLAY](overlay: Overlay): void;
|
|
19
18
|
[UNREGISTER_OVERLAY](overlay: Overlay): void;
|
|
20
19
|
/**
|
|
21
20
|
* Add new overlay to the map. Returns the newly created overlay instance.
|
|
22
21
|
*/
|
|
23
|
-
add(
|
|
22
|
+
add(options: OverlayOptions): Overlay;
|
|
24
23
|
/**
|
|
25
|
-
* Returns list of all current overlays.
|
|
24
|
+
* Returns the list of all current overlays.
|
|
26
25
|
*/
|
|
27
26
|
getAll(): Overlay[];
|
|
27
|
+
/**
|
|
28
|
+
* Destroys all overlays.
|
|
29
|
+
*/
|
|
30
|
+
clear(): void;
|
|
28
31
|
}
|
|
29
32
|
/**
|
|
30
|
-
*
|
|
33
|
+
* Options that define the initial state of an overlay.
|
|
31
34
|
*
|
|
32
35
|
* @group Map Model
|
|
33
36
|
*/
|
|
34
|
-
export interface
|
|
37
|
+
export interface OverlayOptions {
|
|
35
38
|
/**
|
|
36
|
-
* Optional, readonly tag that helps identifying the overlay instance
|
|
39
|
+
* Optional, readonly tag that helps identifying the overlay instance.
|
|
37
40
|
*/
|
|
38
41
|
tag?: string;
|
|
39
42
|
/**
|
|
40
43
|
* Displayed content of the overlay.
|
|
44
|
+
*
|
|
45
|
+
* @see {@link Overlay.setContent}.
|
|
41
46
|
*/
|
|
42
47
|
content?: ReactNode;
|
|
43
48
|
/**
|
|
44
|
-
* CSS classes of the
|
|
49
|
+
* CSS classes of the HTML element that wraps the overlay's content.
|
|
45
50
|
*/
|
|
46
51
|
className?: string;
|
|
47
52
|
/**
|
|
48
|
-
* Role of the
|
|
53
|
+
* Role of the HTML element that wraps the overlay's content.
|
|
49
54
|
*/
|
|
50
55
|
ariaRole?: string;
|
|
51
56
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
57
|
+
* Configures the position of the overlay.
|
|
58
|
+
* The overlay is not rendered if position is `undefined` (the default).
|
|
54
59
|
*
|
|
55
|
-
*
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
*
|
|
60
|
-
*
|
|
60
|
+
* See {@link OverlayPosition} for all supported position options.
|
|
61
|
+
*
|
|
62
|
+
* The following shorthands are available:
|
|
63
|
+
* - A plain `Coordinate` array can be used to specify a static coordinate on the map.
|
|
64
|
+
* - `undefined` hides the overlay.
|
|
65
|
+
* - `"follow-pointer"` can be used as a shorthand to follow the user's cursor.
|
|
61
66
|
*
|
|
62
|
-
*
|
|
67
|
+
* @see {@link Overlay.setPosition} to reconfigure the position.
|
|
68
|
+
* @see {@link Overlay.currentCoordinate} to retrieve the actual position on the map.
|
|
63
69
|
*/
|
|
64
|
-
position?: Coordinate;
|
|
70
|
+
position?: Coordinate | "follow-pointer" | OverlayPosition;
|
|
65
71
|
/**
|
|
66
|
-
* Positioning of an overlay relative to its
|
|
72
|
+
* Positioning of an overlay relative to its coordinates on the map.
|
|
73
|
+
*
|
|
74
|
+
* @see {@link Overlay.setPositioning}
|
|
67
75
|
*/
|
|
68
76
|
positioning?: OverlayPositioning;
|
|
69
77
|
/**
|
|
70
|
-
* Offsets in
|
|
78
|
+
* Offsets in _pixels_ relative to the overlay`s coordinates on the map.
|
|
71
79
|
* The first element in the array is the horizontal offset.
|
|
80
|
+
*
|
|
81
|
+
* @see {@link Overlay.setOffset}
|
|
72
82
|
*/
|
|
73
83
|
offset?: number[];
|
|
74
84
|
/**
|
|
@@ -78,14 +88,55 @@ export interface OverlayProperties {
|
|
|
78
88
|
*/
|
|
79
89
|
stopEvent?: boolean;
|
|
80
90
|
/**
|
|
81
|
-
* Raw OpenLayers overlay properties. `OlOverlayOptions` override corresponding `OverlayProperties
|
|
91
|
+
* Raw OpenLayers overlay properties. `OlOverlayOptions` override corresponding `OverlayProperties`, except for id and element.
|
|
82
92
|
*
|
|
83
|
-
* **warning** Using OpenLayers options can create inconsistencies that lead to errors.
|
|
93
|
+
* **warning** Using OpenLayers options can create inconsistencies that lead to errors.
|
|
94
|
+
* The OpenLayers API can change with updates of OpenLayers.
|
|
84
95
|
*/
|
|
85
96
|
advanced?: OlOverlayOptions;
|
|
86
97
|
}
|
|
87
98
|
/**
|
|
88
|
-
*
|
|
99
|
+
* The configured position of an overlay.
|
|
100
|
+
*
|
|
101
|
+
* @group Map Model
|
|
102
|
+
*/
|
|
103
|
+
export type OverlayPosition =
|
|
104
|
+
/** Explicit (static) coordinates on the map. */
|
|
105
|
+
OverlayPositionCoordinate
|
|
106
|
+
/** Update coordinates based on pointer movements on the map, useful for tooltips. */
|
|
107
|
+
| OverlayPositionFollowPointer;
|
|
108
|
+
/**
|
|
109
|
+
* Automatically positions the overlay on the mouse cursor's coordinates.
|
|
110
|
+
*
|
|
111
|
+
* This can be used, for example, to implement tooltips for map interactions.
|
|
112
|
+
*
|
|
113
|
+
* @group Map Model
|
|
114
|
+
*/
|
|
115
|
+
export interface OverlayPositionFollowPointer {
|
|
116
|
+
kind: "follow-pointer";
|
|
117
|
+
/**
|
|
118
|
+
* The initial coordinates.
|
|
119
|
+
*
|
|
120
|
+
* Use `undefined` (the default) to hide until the first mouse event on the map.
|
|
121
|
+
*/
|
|
122
|
+
initial?: Coordinate;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Places the overlay at the given coordinates.
|
|
126
|
+
*
|
|
127
|
+
* @group Map Model
|
|
128
|
+
*/
|
|
129
|
+
export interface OverlayPositionCoordinate {
|
|
130
|
+
kind: "coordinate";
|
|
131
|
+
/**
|
|
132
|
+
* The explicit coordinates of the overlay on the map.
|
|
133
|
+
*
|
|
134
|
+
* Using `undefined` hides the overlay.
|
|
135
|
+
*/
|
|
136
|
+
coordinate?: Coordinate;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Positioning of an overlay relative to its coordinates on the map.
|
|
89
140
|
*
|
|
90
141
|
* @group Map Model
|
|
91
142
|
*/
|
|
@@ -117,9 +168,11 @@ export declare class Overlay {
|
|
|
117
168
|
* Raw, corresponding OpenLayers overlay object.
|
|
118
169
|
*
|
|
119
170
|
* **warning** Manipulation of the OpenLayers object can create inconsistencies that lead to errors. The OpenLayers API can change with updates of OpenLayers.
|
|
171
|
+
*
|
|
172
|
+
* @see https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html
|
|
120
173
|
*/
|
|
121
174
|
readonly olOverlay: OlOverlay;
|
|
122
|
-
constructor(internalTag: InternalConstructorTag,
|
|
175
|
+
constructor(internalTag: InternalConstructorTag, options: OverlayOptions, parent: Overlays);
|
|
123
176
|
/**
|
|
124
177
|
* Destroys the overlay and removes it from the map.
|
|
125
178
|
* An overlay that is destroyed cannot be added to the map again.
|
|
@@ -130,23 +183,41 @@ export declare class Overlay {
|
|
|
130
183
|
*/
|
|
131
184
|
get isDestroyed(): boolean;
|
|
132
185
|
/**
|
|
133
|
-
*
|
|
186
|
+
* Current coordinates of the overlay on the map.
|
|
187
|
+
*
|
|
188
|
+
* The coordinates on the map are configured via {@link OverlayOptions.position} or {@link setPosition}.
|
|
189
|
+
*
|
|
190
|
+
* - If configured with static coordinates (i.e. `position.kind === "coordinate"`), this is
|
|
191
|
+
* the same as `position.coordinate`.
|
|
192
|
+
* - If configured with `"follow-pointer"` position, this is the result of the user's pointer movements.
|
|
134
193
|
*/
|
|
135
|
-
get
|
|
194
|
+
get currentCoordinate(): Coordinate | undefined;
|
|
136
195
|
/**
|
|
137
|
-
*
|
|
196
|
+
* The content of the overlay that is currently rendered.
|
|
138
197
|
*/
|
|
139
|
-
get
|
|
198
|
+
get content(): ReactNode;
|
|
140
199
|
/**
|
|
141
|
-
* The
|
|
200
|
+
* The HTML element that that wraps the overlay's content.
|
|
142
201
|
*/
|
|
143
202
|
get element(): HTMLElement;
|
|
144
203
|
/**
|
|
145
|
-
*
|
|
204
|
+
* Offset in _pixels_ relative to the overlay`s coordinates.
|
|
205
|
+
*
|
|
206
|
+
* The first element in the array is the horizontal offset.
|
|
146
207
|
*/
|
|
147
208
|
get offset(): number[];
|
|
148
209
|
/**
|
|
149
|
-
*
|
|
210
|
+
* The configured position of the overlay on the map.
|
|
211
|
+
*
|
|
212
|
+
* See also {@link currentCoordinate} to get the coordinate
|
|
213
|
+
* that are the result of this configuration.
|
|
214
|
+
*
|
|
215
|
+
* > NOTE: The return value of the getter may not be the same
|
|
216
|
+
* > as the input to the setter (or constructor) due to normalization.
|
|
217
|
+
*/
|
|
218
|
+
get position(): OverlayPosition;
|
|
219
|
+
/**
|
|
220
|
+
* Positioning of an overlay relative to its coordinates on the map.
|
|
150
221
|
*/
|
|
151
222
|
get positioning(): OverlayPositioning;
|
|
152
223
|
/**
|
|
@@ -154,17 +225,24 @@ export declare class Overlay {
|
|
|
154
225
|
*/
|
|
155
226
|
setContent(content: ReactNode): void;
|
|
156
227
|
/**
|
|
157
|
-
* Set the
|
|
228
|
+
* Set the position of the overlay.
|
|
229
|
+
*
|
|
230
|
+
* This controls the coordinates of the map.
|
|
231
|
+
* The overlay is not rendered if the coordinates are `undefined`.
|
|
158
232
|
*
|
|
159
|
-
*
|
|
233
|
+
* See also {@link currentCoordinate} to get the coordinates
|
|
234
|
+
* that are the result of this configuration.
|
|
235
|
+
*
|
|
236
|
+
* @see {@link OverlayPosition}
|
|
160
237
|
*/
|
|
161
|
-
setPosition(position:
|
|
238
|
+
setPosition(position: OverlayOptions["position"]): void;
|
|
162
239
|
/**
|
|
163
|
-
* Set offset in
|
|
240
|
+
* Set offset in _pixels_ relative to the overlay`s coordinates on the map.
|
|
241
|
+
* The first element in the array is the horizontal offset.
|
|
164
242
|
*/
|
|
165
243
|
setOffset(offset: number[]): void;
|
|
166
244
|
/**
|
|
167
|
-
* Set positioning of an overlay relative to its
|
|
245
|
+
* Set positioning of an overlay relative to its coordinates on the map.
|
|
168
246
|
*/
|
|
169
247
|
setPositioning(positioning: OverlayPositioning): void;
|
|
170
248
|
}
|
package/model/Overlays.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Overlay as Overlay$1 } from 'ol';
|
|
2
|
-
import { reactiveSet, reactive, synchronized, batch } from '@conterra/reactivity-core';
|
|
2
|
+
import { reactiveSet, reactive, synchronized, watchValue, batch } from '@conterra/reactivity-core';
|
|
3
3
|
import { v4 } from 'uuid';
|
|
4
4
|
import { createLogger, destroyResources } from '@open-pioneer/core';
|
|
5
5
|
import { unByKey } from 'ol/Observable.js';
|
|
@@ -10,37 +10,45 @@ const REGISTER_OVERLAY = /* @__PURE__ */ Symbol("REGISTER_OVERLAY");
|
|
|
10
10
|
const UNREGISTER_OVERLAY = /* @__PURE__ */ Symbol("UNREGISTER_OVERLAY");
|
|
11
11
|
const LOG = createLogger(sourceId);
|
|
12
12
|
class Overlays {
|
|
13
|
-
olMap;
|
|
14
|
-
overlays = reactiveSet();
|
|
13
|
+
#olMap;
|
|
14
|
+
#overlays = reactiveSet();
|
|
15
15
|
constructor(map) {
|
|
16
|
-
this
|
|
16
|
+
this.#olMap = map.olMap;
|
|
17
17
|
}
|
|
18
18
|
[REGISTER_OVERLAY](overlay) {
|
|
19
|
-
if (this
|
|
19
|
+
if (this.#overlays.has(overlay)) {
|
|
20
20
|
throw new Error("Internal error: overlay is already registered");
|
|
21
21
|
}
|
|
22
|
-
this
|
|
23
|
-
this
|
|
22
|
+
this.#overlays.add(overlay);
|
|
23
|
+
this.#olMap.addOverlay(overlay.olOverlay);
|
|
24
24
|
}
|
|
25
25
|
[UNREGISTER_OVERLAY](overlay) {
|
|
26
|
-
if (!this
|
|
26
|
+
if (!this.#overlays.has(overlay)) {
|
|
27
27
|
throw new Error("Internal error: overlay was not registered");
|
|
28
28
|
}
|
|
29
|
-
this
|
|
30
|
-
this
|
|
29
|
+
this.#overlays.delete(overlay);
|
|
30
|
+
this.#olMap.removeOverlay(overlay.olOverlay);
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Add new overlay to the map. Returns the newly created overlay instance.
|
|
34
34
|
*/
|
|
35
|
-
add(
|
|
36
|
-
const newModel = new Overlay(INTERNAL_CONSTRUCTOR_TAG,
|
|
35
|
+
add(options) {
|
|
36
|
+
const newModel = new Overlay(INTERNAL_CONSTRUCTOR_TAG, options, this);
|
|
37
37
|
return newModel;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* Returns list of all current overlays.
|
|
40
|
+
* Returns the list of all current overlays.
|
|
41
41
|
*/
|
|
42
42
|
getAll() {
|
|
43
|
-
return Array.from(this
|
|
43
|
+
return Array.from(this.#overlays);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Destroys all overlays.
|
|
47
|
+
*/
|
|
48
|
+
clear() {
|
|
49
|
+
for (const overlay of this.#overlays) {
|
|
50
|
+
overlay.destroy();
|
|
51
|
+
}
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
class Overlay {
|
|
@@ -58,14 +66,17 @@ class Overlay {
|
|
|
58
66
|
* Raw, corresponding OpenLayers overlay object.
|
|
59
67
|
*
|
|
60
68
|
* **warning** Manipulation of the OpenLayers object can create inconsistencies that lead to errors. The OpenLayers API can change with updates of OpenLayers.
|
|
69
|
+
*
|
|
70
|
+
* @see https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html
|
|
61
71
|
*/
|
|
62
72
|
olOverlay;
|
|
63
73
|
#parent;
|
|
64
74
|
#isDestroyed = reactive(false);
|
|
75
|
+
#position = reactive({ kind: "coordinate" });
|
|
65
76
|
#content;
|
|
66
|
-
#resources;
|
|
67
77
|
#overlayDiv;
|
|
68
|
-
#
|
|
78
|
+
#resources = [];
|
|
79
|
+
#coordinate = synchronized(
|
|
69
80
|
() => this.olOverlay.getPosition(),
|
|
70
81
|
(cb) => {
|
|
71
82
|
const key = this.olOverlay.on("change:position", cb);
|
|
@@ -86,40 +97,61 @@ class Overlay {
|
|
|
86
97
|
return () => unByKey(key);
|
|
87
98
|
}
|
|
88
99
|
);
|
|
89
|
-
constructor(internalTag,
|
|
100
|
+
constructor(internalTag, options, parent) {
|
|
90
101
|
if (internalTag !== INTERNAL_CONSTRUCTOR_TAG) {
|
|
91
102
|
throw new Error("The overlay constructor is private.");
|
|
92
103
|
}
|
|
93
|
-
const {
|
|
104
|
+
const {
|
|
105
|
+
className,
|
|
106
|
+
ariaRole,
|
|
107
|
+
position,
|
|
108
|
+
tag,
|
|
109
|
+
content,
|
|
110
|
+
offset,
|
|
111
|
+
positioning,
|
|
112
|
+
stopEvent,
|
|
113
|
+
advanced
|
|
114
|
+
} = options;
|
|
94
115
|
this.id = v4();
|
|
95
|
-
this.tag =
|
|
116
|
+
this.tag = tag;
|
|
96
117
|
this.#overlayDiv = createElement(ariaRole, className);
|
|
97
|
-
if (!properties.mode) {
|
|
98
|
-
properties.mode = "set-position";
|
|
99
|
-
}
|
|
100
|
-
const mergedProperties = !copyProperties.advanced ? copyProperties : { ...copyProperties, ...copyProperties.advanced };
|
|
101
118
|
this.olOverlay = new Overlay$1({
|
|
102
119
|
element: this.#overlayDiv,
|
|
103
120
|
id: this.id,
|
|
104
|
-
|
|
121
|
+
offset,
|
|
122
|
+
positioning,
|
|
123
|
+
stopEvent,
|
|
124
|
+
//simply override with advanced OL Options if set
|
|
125
|
+
...advanced
|
|
105
126
|
});
|
|
106
127
|
this.#parent = parent;
|
|
107
|
-
this.#content = reactive(
|
|
108
|
-
this
|
|
128
|
+
this.#content = reactive(content);
|
|
129
|
+
this.setPosition(position);
|
|
109
130
|
parent[REGISTER_OVERLAY](this);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
this.#resources.push(
|
|
132
|
+
// Update coordinate based on pointer movements when configured.
|
|
133
|
+
// Automatically subscribes and unsubscribes on changes.
|
|
134
|
+
watchValue(
|
|
135
|
+
() => this.#position.value?.kind === "follow-pointer",
|
|
136
|
+
(followPointer) => {
|
|
137
|
+
if (!followPointer) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const olMap = this.olOverlay.getMap();
|
|
141
|
+
if (!olMap) {
|
|
142
|
+
LOG.error(
|
|
143
|
+
`Overlay ${this.olOverlay.getId()} is not registered with a map.`
|
|
144
|
+
);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const pointerMoveKey = olMap.on("pointermove", (e) => {
|
|
148
|
+
this.olOverlay.setPosition(e.coordinate);
|
|
149
|
+
});
|
|
150
|
+
return () => unByKey(pointerMoveKey);
|
|
151
|
+
},
|
|
152
|
+
{ immediate: true, dispatch: "sync" }
|
|
153
|
+
)
|
|
154
|
+
);
|
|
123
155
|
}
|
|
124
156
|
/**
|
|
125
157
|
* Destroys the overlay and removes it from the map.
|
|
@@ -143,31 +175,51 @@ class Overlay {
|
|
|
143
175
|
return this.#isDestroyed.value;
|
|
144
176
|
}
|
|
145
177
|
/**
|
|
146
|
-
*
|
|
178
|
+
* Current coordinates of the overlay on the map.
|
|
179
|
+
*
|
|
180
|
+
* The coordinates on the map are configured via {@link OverlayOptions.position} or {@link setPosition}.
|
|
181
|
+
*
|
|
182
|
+
* - If configured with static coordinates (i.e. `position.kind === "coordinate"`), this is
|
|
183
|
+
* the same as `position.coordinate`.
|
|
184
|
+
* - If configured with `"follow-pointer"` position, this is the result of the user's pointer movements.
|
|
147
185
|
*/
|
|
148
|
-
get
|
|
149
|
-
return this.#
|
|
186
|
+
get currentCoordinate() {
|
|
187
|
+
return this.#coordinate.value;
|
|
150
188
|
}
|
|
151
189
|
/**
|
|
152
|
-
*
|
|
190
|
+
* The content of the overlay that is currently rendered.
|
|
153
191
|
*/
|
|
154
|
-
get
|
|
155
|
-
return this.#
|
|
192
|
+
get content() {
|
|
193
|
+
return this.#content.value;
|
|
156
194
|
}
|
|
157
195
|
/**
|
|
158
|
-
* The
|
|
196
|
+
* The HTML element that that wraps the overlay's content.
|
|
159
197
|
*/
|
|
160
198
|
get element() {
|
|
161
199
|
return this.#overlayDiv;
|
|
162
200
|
}
|
|
163
201
|
/**
|
|
164
|
-
*
|
|
202
|
+
* Offset in _pixels_ relative to the overlay`s coordinates.
|
|
203
|
+
*
|
|
204
|
+
* The first element in the array is the horizontal offset.
|
|
165
205
|
*/
|
|
166
206
|
get offset() {
|
|
167
207
|
return this.#offset.value;
|
|
168
208
|
}
|
|
169
209
|
/**
|
|
170
|
-
*
|
|
210
|
+
* The configured position of the overlay on the map.
|
|
211
|
+
*
|
|
212
|
+
* See also {@link currentCoordinate} to get the coordinate
|
|
213
|
+
* that are the result of this configuration.
|
|
214
|
+
*
|
|
215
|
+
* > NOTE: The return value of the getter may not be the same
|
|
216
|
+
* > as the input to the setter (or constructor) due to normalization.
|
|
217
|
+
*/
|
|
218
|
+
get position() {
|
|
219
|
+
return this.#position.value;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Positioning of an overlay relative to its coordinates on the map.
|
|
171
223
|
*/
|
|
172
224
|
get positioning() {
|
|
173
225
|
return this.#positioning.value;
|
|
@@ -179,26 +231,57 @@ class Overlay {
|
|
|
179
231
|
this.#content.value = content;
|
|
180
232
|
}
|
|
181
233
|
/**
|
|
182
|
-
* Set the
|
|
234
|
+
* Set the position of the overlay.
|
|
235
|
+
*
|
|
236
|
+
* This controls the coordinates of the map.
|
|
237
|
+
* The overlay is not rendered if the coordinates are `undefined`.
|
|
183
238
|
*
|
|
184
|
-
*
|
|
239
|
+
* See also {@link currentCoordinate} to get the coordinates
|
|
240
|
+
* that are the result of this configuration.
|
|
241
|
+
*
|
|
242
|
+
* @see {@link OverlayPosition}
|
|
185
243
|
*/
|
|
186
244
|
setPosition(position) {
|
|
187
|
-
|
|
245
|
+
const normalized = normalizePosition(position);
|
|
246
|
+
let newCoordinate;
|
|
247
|
+
if (normalized) {
|
|
248
|
+
if (normalized.kind === "coordinate") {
|
|
249
|
+
newCoordinate = normalized.coordinate;
|
|
250
|
+
} else {
|
|
251
|
+
newCoordinate = normalized.initial;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
batch(() => {
|
|
255
|
+
this.#position.value = normalized;
|
|
256
|
+
this.olOverlay.setPosition(newCoordinate);
|
|
257
|
+
});
|
|
188
258
|
}
|
|
189
259
|
/**
|
|
190
|
-
* Set offset in
|
|
260
|
+
* Set offset in _pixels_ relative to the overlay`s coordinates on the map.
|
|
261
|
+
* The first element in the array is the horizontal offset.
|
|
191
262
|
*/
|
|
192
263
|
setOffset(offset) {
|
|
193
264
|
this.olOverlay.setOffset(offset);
|
|
194
265
|
}
|
|
195
266
|
/**
|
|
196
|
-
* Set positioning of an overlay relative to its
|
|
267
|
+
* Set positioning of an overlay relative to its coordinates on the map.
|
|
197
268
|
*/
|
|
198
269
|
setPositioning(positioning) {
|
|
199
270
|
this.olOverlay.setPositioning(positioning);
|
|
200
271
|
}
|
|
201
272
|
}
|
|
273
|
+
function normalizePosition(position) {
|
|
274
|
+
if (!position || Array.isArray(position)) {
|
|
275
|
+
return { kind: "coordinate", coordinate: position };
|
|
276
|
+
}
|
|
277
|
+
if (position === "follow-pointer") {
|
|
278
|
+
return { kind: "follow-pointer" };
|
|
279
|
+
}
|
|
280
|
+
if (typeof position !== "object") {
|
|
281
|
+
throw new Error("Unexpected position: " + position);
|
|
282
|
+
}
|
|
283
|
+
return position;
|
|
284
|
+
}
|
|
202
285
|
function createElement(ariaRole, classNameProp) {
|
|
203
286
|
const overlayDiv = document.createElement("div");
|
|
204
287
|
if (ariaRole) {
|
package/model/Overlays.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Overlays.js","sources":["Overlays.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Map as OlMap, Overlay as OlOverlay } from \"ol\";\nimport { MapModel } from \"./MapModel\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { ReactNode } from \"react\";\nimport { batch, reactive, Reactive, reactiveSet, synchronized } from \"@conterra/reactivity-core\";\nimport { v4 as uuid4v } from \"uuid\";\nimport { createLogger, destroyResources, Resource } from \"@open-pioneer/core\";\nimport { EventsKey } from \"ol/events\";\nimport { unByKey } from \"ol/Observable\";\nimport { Options } from \"ol/Overlay\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { INTERNAL_CONSTRUCTOR_TAG, InternalConstructorTag } from \"../utils/InternalConstructorTag\";\n\nexport const REGISTER_OVERLAY = Symbol(\"REGISTER_OVERLAY\");\nexport const UNREGISTER_OVERLAY = Symbol(\"UNREGISTER_OVERLAY\");\n\nconst LOG = createLogger(sourceId);\n\n/**\n * Manages active overlays on the map.\n *\n * @group Map Model\n */\nexport class Overlays {\n private olMap: OlMap;\n private overlays = reactiveSet<Overlay>();\n\n constructor(map: MapModel) {\n this.olMap = map.olMap;\n }\n\n [REGISTER_OVERLAY](overlay: Overlay) {\n if (this.overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay is already registered\");\n }\n this.overlays.add(overlay);\n this.olMap.addOverlay(overlay.olOverlay);\n }\n\n [UNREGISTER_OVERLAY](overlay: Overlay) {\n if (!this.overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay was not registered\");\n }\n this.overlays.delete(overlay);\n this.olMap.removeOverlay(overlay.olOverlay);\n }\n\n /**\n * Add new overlay to the map. Returns the newly created overlay instance.\n */\n add(properties: OverlayProperties): Overlay {\n const newModel = new Overlay(INTERNAL_CONSTRUCTOR_TAG, properties, this);\n return newModel;\n }\n\n /**\n * Returns list of all current overlays.\n */\n getAll(): Overlay[] {\n return Array.from(this.overlays);\n }\n}\n\n/**\n * Properties that define the initial state of an overlay.\n *\n * @group Map Model\n */\nexport interface OverlayProperties {\n /**\n * Optional, readonly tag that helps identifying the overlay instance\n */\n tag?: string;\n\n /**\n * Displayed content of the overlay.\n */\n content?: ReactNode;\n\n /**\n * CSS classes of the HTMLDivElement that wraps the overlay's content.\n */\n className?: string;\n\n /**\n * Role of the HTMLDivElement that wraps the overlay's content.\n */\n ariaRole?: string;\n\n /**\n * If mode is `set-position` the overlay remains at the provided position. The position can be changed manually by calling `setPosition` on the overlay instance.\n * If mode is `follow-pointer` the position is automatically updated to pointer position (coordinates) on the map.\n *\n * By default the mode is `set-position`.\n */\n mode?: \"set-position\" | \"follow-pointer\"; //ToDo there might be a better name instead of set-position\n\n /**\n * Initial position of the overlay. Overlay is not rendered if position is `undefined`.\n * Can be overridden immediately if `mode` is `follow-pointer`\n *\n * ToDo: Makes no sense to provide coordinate if mode is follow-pointer, How to model this with Typescript? (also setPosition of Overlay)\n */\n position?: Coordinate;\n\n /**\n * Positioning of an overlay relative to its position (coordinates).\n */\n positioning?: OverlayPositioning;\n\n /**\n * Offsets in pixels relative to the overlay`s position (coordinates).\n * The first element in the array is the horizontal offset.\n */\n offset?: number[];\n\n /**\n * Determines if event propagation to the map viewport should be stopped.\n *\n * By default `stopEvent` is `true`.\n */\n stopEvent?: boolean;\n\n /**\n * Raw OpenLayers overlay properties. `OlOverlayOptions` override corresponding `OverlayProperties` except id and element.\n *\n * **warning** Using OpenLayers options can create inconsistencies that lead to errors. The OpenLayers API can change with updates of OpenLayers.\n */\n advanced?: OlOverlayOptions; //raw OL properties, overrides mutual properties from outer OverlayProperties (except id and element?)\n}\n\n/**\n * Positioning of an overlay relative to its position (coordinates).\n *\n * @group Map Model\n */\nexport type OverlayPositioning =\n | \"bottom-left\"\n | \"bottom-center\"\n | \"bottom-right\"\n | \"center-left\"\n | \"center-center\"\n | \"center-right\"\n | \"top-left\"\n | \"top-center\"\n | \"top-right\";\n\n/** @group Map Model */\nexport interface OlOverlayOptions extends Omit<Partial<Options>, \"id\" | \"element\"> {}\n\n/**\n * An overlay is an UI element that is displayed over the map.\n *\n * Overlays are tied to coordinates on the map and not to a position on the screen.\n * The overlay renders a react node at the specified coordinates.\n *\n * @group Map Model\n */\nexport class Overlay {\n /**\n * Unique, readonly id of the overlay.\n *\n * Automatically assigned when the overlay is created. Use the `tag` property for custom identifiers.\n */\n readonly id: string;\n\n /**\n * Optional, readonly tag that helps identifying the overlay instance.\n */\n readonly tag: string | undefined;\n\n /**\n * Raw, corresponding OpenLayers overlay object.\n *\n * **warning** Manipulation of the OpenLayers object can create inconsistencies that lead to errors. The OpenLayers API can change with updates of OpenLayers.\n */\n readonly olOverlay: OlOverlay;\n\n #parent: Overlays;\n #isDestroyed = reactive(false);\n #content: Reactive<ReactNode>;\n #resources: Resource[];\n #overlayDiv: HTMLDivElement;\n\n #position = synchronized(\n () => this.olOverlay.getPosition(),\n (cb) => {\n const key = this.olOverlay.on(\"change:position\", cb);\n return () => unByKey(key);\n }\n );\n #positioning = synchronized(\n () => this.olOverlay.getPositioning(),\n (cb) => {\n const key = this.olOverlay.on(\"change:positioning\", cb);\n return () => unByKey(key);\n }\n );\n #offset = synchronized(\n () => this.olOverlay.getOffset(),\n (cb) => {\n const key = this.olOverlay.on(\"change:offset\", cb);\n return () => unByKey(key);\n }\n );\n\n constructor(\n internalTag: InternalConstructorTag,\n properties: OverlayProperties,\n parent: Overlays\n ) {\n if (internalTag !== INTERNAL_CONSTRUCTOR_TAG) {\n throw new Error(\"The overlay constructor is private.\");\n }\n\n const { className, ariaRole, mode, ...copyProperties } = properties;\n this.id = uuid4v();\n this.tag = properties.tag;\n this.#overlayDiv = createElement(ariaRole, className);\n\n if (!properties.mode) {\n properties.mode = \"set-position\";\n }\n\n //simply override with advanced OL Options if set\n const mergedProperties = !copyProperties.advanced\n ? copyProperties\n : { ...copyProperties, ...copyProperties.advanced };\n\n this.olOverlay = new OlOverlay({\n element: this.#overlayDiv,\n id: this.id,\n ...mergedProperties\n });\n this.#parent = parent;\n this.#content = reactive(properties.content);\n this.#resources = [];\n\n parent[REGISTER_OVERLAY](this);\n\n if (mode === \"follow-pointer\") {\n //olMap is set after registration\n const olMap = this.olOverlay.getMap();\n if (!olMap) {\n LOG.error(`Error: Overlay ${this.olOverlay.getId()} is not registered at a map.`);\n return;\n }\n\n const pointerMoveKey: EventsKey = olMap.on(\"pointermove\", (e) => {\n this.setPosition(e.coordinate);\n });\n this.#resources.push({\n destroy: () => unByKey(pointerMoveKey)\n });\n }\n }\n\n /**\n * Destroys the overlay and removes it from the map.\n * An overlay that is destroyed cannot be added to the map again.\n */\n destroy(): void {\n if (this.isDestroyed) {\n return;\n }\n\n batch(() => {\n this.#isDestroyed.value = true;\n this.#parent[UNREGISTER_OVERLAY](this);\n this.olOverlay.dispose();\n destroyResources(this.#resources);\n });\n }\n\n /**\n * Indicates if the overlay instance has been destroyed.\n */\n get isDestroyed(): boolean {\n return this.#isDestroyed.value;\n }\n\n /**\n * The content of the overlay that is currently rendered.\n */\n get content(): ReactNode {\n return this.#content.value;\n }\n\n /**\n * Current position (coordinates) of the overlay.\n */\n get position(): Coordinate | undefined {\n return this.#position.value;\n }\n\n /**\n * The HTMLDivElement that that wraps the overlay's content.\n */\n get element(): HTMLElement {\n return this.#overlayDiv;\n }\n\n /**\n * Offsets in pixels relative to the overlay`s position. The first element in the array is the horizontal offset.\n */\n get offset(): number[] {\n return this.#offset.value;\n }\n\n /**\n * Positioning of an overlay relative to its position (coordinates).\n */\n get positioning(): OverlayPositioning {\n return this.#positioning.value;\n }\n\n /**\n * Set new content that is rendered on the overlay.\n */\n setContent(content: ReactNode): void {\n this.#content.value = content;\n }\n\n /**\n * Set the coordinates of the overlay. The overlay is not rendered if the position is `undefined`.\n *\n * Can be overridden immediately if the overlay's `mode` is `follow-pointer` (see {@link OverlayProperties}).\n */\n setPosition(position: Coordinate | undefined) {\n this.olOverlay.setPosition(position);\n }\n\n /**\n * Set offset in pixels relative to the overlay`s position. The first element in the array is the horizontal offset.\n */\n setOffset(offset: number[]) {\n this.olOverlay.setOffset(offset);\n }\n\n /**\n * Set positioning of an overlay relative to its position (coordinates)\n */\n setPositioning(positioning: OverlayPositioning) {\n this.olOverlay.setPositioning(positioning);\n }\n}\n\nfunction createElement(ariaRole: string | undefined, classNameProp: string | undefined) {\n const overlayDiv = document.createElement(\"div\");\n if (ariaRole) {\n overlayDiv.role = ariaRole;\n }\n\n let className = \"map-overlay\";\n if (classNameProp) {\n className += ` ${classNameProp}`;\n }\n overlayDiv.className = className;\n return overlayDiv;\n}\n"],"names":["uuid4v","OlOverlay"],"mappings":";;;;;;;;AAgBO,MAAM,gBAAA,0BAA0B,kBAAkB,CAAA;AAClD,MAAM,kBAAA,0BAA4B,oBAAoB,CAAA;AAE7D,MAAM,GAAA,GAAM,aAAa,QAAQ,CAAA;AAO1B,MAAM,QAAA,CAAS;AAAA,EACV,KAAA;AAAA,EACA,WAAW,WAAA,EAAqB;AAAA,EAExC,YAAY,GAAA,EAAe;AACvB,IAAA,IAAA,CAAK,QAAQ,GAAA,CAAI,KAAA;AAAA,EACrB;AAAA,EAEA,CAAC,gBAAgB,CAAA,CAAE,OAAA,EAAkB;AACjC,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA,EAAG;AAC5B,MAAA,MAAM,IAAI,MAAM,+CAA+C,CAAA;AAAA,IACnE;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,IAAI,OAAO,CAAA;AACzB,IAAA,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,OAAA,CAAQ,SAAS,CAAA;AAAA,EAC3C;AAAA,EAEA,CAAC,kBAAkB,CAAA,CAAE,OAAA,EAAkB;AACnC,IAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA,EAAG;AAC7B,MAAA,MAAM,IAAI,MAAM,4CAA4C,CAAA;AAAA,IAChE;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,OAAO,OAAO,CAAA;AAC5B,IAAA,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,OAAA,CAAQ,SAAS,CAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAA,EAAwC;AACxC,IAAA,MAAM,QAAA,GAAW,IAAI,OAAA,CAAQ,wBAAA,EAA0B,YAAY,IAAI,CAAA;AACvE,IAAA,OAAO,QAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA,GAAoB;AAChB,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA;AAAA,EACnC;AACJ;AAiGO,MAAM,OAAA,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,EAAA;AAAA;AAAA;AAAA;AAAA,EAKA,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAA;AAAA,EAET,OAAA;AAAA,EACA,YAAA,GAAe,SAAS,KAAK,CAAA;AAAA,EAC7B,QAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EAEA,SAAA,GAAY,YAAA;AAAA,IACR,MAAM,IAAA,CAAK,SAAA,CAAU,WAAA,EAAY;AAAA,IACjC,CAAC,EAAA,KAAO;AACJ,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,mBAAmB,EAAE,CAAA;AACnD,MAAA,OAAO,MAAM,QAAQ,GAAG,CAAA;AAAA,IAC5B;AAAA,GACJ;AAAA,EACA,YAAA,GAAe,YAAA;AAAA,IACX,MAAM,IAAA,CAAK,SAAA,CAAU,cAAA,EAAe;AAAA,IACpC,CAAC,EAAA,KAAO;AACJ,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,sBAAsB,EAAE,CAAA;AACtD,MAAA,OAAO,MAAM,QAAQ,GAAG,CAAA;AAAA,IAC5B;AAAA,GACJ;AAAA,EACA,OAAA,GAAU,YAAA;AAAA,IACN,MAAM,IAAA,CAAK,SAAA,CAAU,SAAA,EAAU;AAAA,IAC/B,CAAC,EAAA,KAAO;AACJ,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,iBAAiB,EAAE,CAAA;AACjD,MAAA,OAAO,MAAM,QAAQ,GAAG,CAAA;AAAA,IAC5B;AAAA,GACJ;AAAA,EAEA,WAAA,CACI,WAAA,EACA,UAAA,EACA,MAAA,EACF;AACE,IAAA,IAAI,gBAAgB,wBAAA,EAA0B;AAC1C,MAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,IACzD;AAEA,IAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,IAAA,EAAM,GAAG,gBAAe,GAAI,UAAA;AACzD,IAAA,IAAA,CAAK,KAAKA,EAAA,EAAO;AACjB,IAAA,IAAA,CAAK,MAAM,UAAA,CAAW,GAAA;AACtB,IAAA,IAAA,CAAK,WAAA,GAAc,aAAA,CAAc,QAAA,EAAU,SAAS,CAAA;AAEpD,IAAA,IAAI,CAAC,WAAW,IAAA,EAAM;AAClB,MAAA,UAAA,CAAW,IAAA,GAAO,cAAA;AAAA,IACtB;AAGA,IAAA,MAAM,gBAAA,GAAmB,CAAC,cAAA,CAAe,QAAA,GACnC,cAAA,GACA,EAAE,GAAG,cAAA,EAAgB,GAAG,cAAA,CAAe,QAAA,EAAS;AAEtD,IAAA,IAAA,CAAK,SAAA,GAAY,IAAIC,SAAA,CAAU;AAAA,MAC3B,SAAS,IAAA,CAAK,WAAA;AAAA,MACd,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,GAAG;AAAA,KACN,CAAA;AACD,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA,CAAS,UAAA,CAAW,OAAO,CAAA;AAC3C,IAAA,IAAA,CAAK,aAAa,EAAC;AAEnB,IAAA,MAAA,CAAO,gBAAgB,EAAE,IAAI,CAAA;AAE7B,IAAA,IAAI,SAAS,gBAAA,EAAkB;AAE3B,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAU,MAAA,EAAO;AACpC,MAAA,IAAI,CAAC,KAAA,EAAO;AACR,QAAA,GAAA,CAAI,MAAM,CAAA,eAAA,EAAkB,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,CAAA,4BAAA,CAA8B,CAAA;AAChF,QAAA;AAAA,MACJ;AAEA,MAAA,MAAM,cAAA,GAA4B,KAAA,CAAM,EAAA,CAAG,aAAA,EAAe,CAAC,CAAA,KAAM;AAC7D,QAAA,IAAA,CAAK,WAAA,CAAY,EAAE,UAAU,CAAA;AAAA,MACjC,CAAC,CAAA;AACD,MAAA,IAAA,CAAK,WAAW,IAAA,CAAK;AAAA,QACjB,OAAA,EAAS,MAAM,OAAA,CAAQ,cAAc;AAAA,OACxC,CAAA;AAAA,IACL;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAA,GAAgB;AACZ,IAAA,IAAI,KAAK,WAAA,EAAa;AAClB,MAAA;AAAA,IACJ;AAEA,IAAA,KAAA,CAAM,MAAM;AACR,MAAA,IAAA,CAAK,aAAa,KAAA,GAAQ,IAAA;AAC1B,MAAA,IAAA,CAAK,OAAA,CAAQ,kBAAkB,CAAA,CAAE,IAAI,CAAA;AACrC,MAAA,IAAA,CAAK,UAAU,OAAA,EAAQ;AACvB,MAAA,gBAAA,CAAiB,KAAK,UAAU,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAA,GAAuB;AACvB,IAAA,OAAO,KAAK,YAAA,CAAa,KAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAA,GAAqB;AACrB,IAAA,OAAO,KAAK,QAAA,CAAS,KAAA;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,QAAA,GAAmC;AACnC,IAAA,OAAO,KAAK,SAAA,CAAU,KAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAA,GAAuB;AACvB,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAA,GAAmB;AACnB,IAAA,OAAO,KAAK,OAAA,CAAQ,KAAA;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAA,GAAkC;AAClC,IAAA,OAAO,KAAK,YAAA,CAAa,KAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,OAAA,EAA0B;AACjC,IAAA,IAAA,CAAK,SAAS,KAAA,GAAQ,OAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,QAAA,EAAkC;AAC1C,IAAA,IAAA,CAAK,SAAA,CAAU,YAAY,QAAQ,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAA,EAAkB;AACxB,IAAA,IAAA,CAAK,SAAA,CAAU,UAAU,MAAM,CAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,WAAA,EAAiC;AAC5C,IAAA,IAAA,CAAK,SAAA,CAAU,eAAe,WAAW,CAAA;AAAA,EAC7C;AACJ;AAEA,SAAS,aAAA,CAAc,UAA8B,aAAA,EAAmC;AACpF,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC/C,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,UAAA,CAAW,IAAA,GAAO,QAAA;AAAA,EACtB;AAEA,EAAA,IAAI,SAAA,GAAY,aAAA;AAChB,EAAA,IAAI,aAAA,EAAe;AACf,IAAA,SAAA,IAAa,IAAI,aAAa,CAAA,CAAA;AAAA,EAClC;AACA,EAAA,UAAA,CAAW,SAAA,GAAY,SAAA;AACvB,EAAA,OAAO,UAAA;AACX;;;;"}
|
|
1
|
+
{"version":3,"file":"Overlays.js","sources":["Overlays.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Map as OlMap, Overlay as OlOverlay } from \"ol\";\nimport { MapModel } from \"./MapModel\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { ReactNode } from \"react\";\nimport {\n batch,\n reactive,\n Reactive,\n reactiveSet,\n synchronized,\n watchValue\n} from \"@conterra/reactivity-core\";\nimport { v4 as uuid4v } from \"uuid\";\nimport { createLogger, destroyResources, Resource } from \"@open-pioneer/core\";\nimport { EventsKey } from \"ol/events\";\nimport { unByKey } from \"ol/Observable\";\nimport { Options } from \"ol/Overlay\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { INTERNAL_CONSTRUCTOR_TAG, InternalConstructorTag } from \"../utils/InternalConstructorTag\";\n\nexport const REGISTER_OVERLAY = Symbol(\"REGISTER_OVERLAY\");\nexport const UNREGISTER_OVERLAY = Symbol(\"UNREGISTER_OVERLAY\");\n\nconst LOG = createLogger(sourceId);\n\n/**\n * Manages active overlays on the map.\n *\n * @group Map Model\n */\nexport class Overlays {\n #olMap: OlMap;\n #overlays = reactiveSet<Overlay>();\n\n constructor(map: MapModel) {\n this.#olMap = map.olMap;\n }\n\n [REGISTER_OVERLAY](overlay: Overlay) {\n if (this.#overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay is already registered\");\n }\n this.#overlays.add(overlay);\n this.#olMap.addOverlay(overlay.olOverlay);\n }\n\n [UNREGISTER_OVERLAY](overlay: Overlay) {\n if (!this.#overlays.has(overlay)) {\n throw new Error(\"Internal error: overlay was not registered\");\n }\n this.#overlays.delete(overlay);\n this.#olMap.removeOverlay(overlay.olOverlay);\n }\n\n /**\n * Add new overlay to the map. Returns the newly created overlay instance.\n */\n add(options: OverlayOptions): Overlay {\n const newModel = new Overlay(INTERNAL_CONSTRUCTOR_TAG, options, this);\n return newModel;\n }\n\n /**\n * Returns the list of all current overlays.\n */\n getAll(): Overlay[] {\n return Array.from(this.#overlays);\n }\n\n /**\n * Destroys all overlays.\n */\n clear(): void {\n for (const overlay of this.#overlays) {\n overlay.destroy();\n }\n }\n}\n\n/**\n * Options that define the initial state of an overlay.\n *\n * @group Map Model\n */\nexport interface OverlayOptions {\n /**\n * Optional, readonly tag that helps identifying the overlay instance.\n */\n tag?: string;\n\n /**\n * Displayed content of the overlay.\n *\n * @see {@link Overlay.setContent}.\n */\n content?: ReactNode;\n\n /**\n * CSS classes of the HTML element that wraps the overlay's content.\n */\n className?: string;\n\n /**\n * Role of the HTML element that wraps the overlay's content.\n */\n ariaRole?: string;\n\n /**\n * Configures the position of the overlay.\n * The overlay is not rendered if position is `undefined` (the default).\n *\n * See {@link OverlayPosition} for all supported position options.\n *\n * The following shorthands are available:\n * - A plain `Coordinate` array can be used to specify a static coordinate on the map.\n * - `undefined` hides the overlay.\n * - `\"follow-pointer\"` can be used as a shorthand to follow the user's cursor.\n *\n * @see {@link Overlay.setPosition} to reconfigure the position.\n * @see {@link Overlay.currentCoordinate} to retrieve the actual position on the map.\n */\n position?: Coordinate | \"follow-pointer\" | OverlayPosition;\n\n /**\n * Positioning of an overlay relative to its coordinates on the map.\n *\n * @see {@link Overlay.setPositioning}\n */\n positioning?: OverlayPositioning;\n\n /**\n * Offsets in _pixels_ relative to the overlay`s coordinates on the map.\n * The first element in the array is the horizontal offset.\n *\n * @see {@link Overlay.setOffset}\n */\n offset?: number[];\n\n /**\n * Determines if event propagation to the map viewport should be stopped.\n *\n * By default `stopEvent` is `true`.\n */\n stopEvent?: boolean;\n\n /**\n * Raw OpenLayers overlay properties. `OlOverlayOptions` override corresponding `OverlayProperties`, except for id and element.\n *\n * **warning** Using OpenLayers options can create inconsistencies that lead to errors.\n * The OpenLayers API can change with updates of OpenLayers.\n */\n advanced?: OlOverlayOptions;\n}\n\n/**\n * The configured position of an overlay.\n *\n * @group Map Model\n */\nexport type OverlayPosition =\n /** Explicit (static) coordinates on the map. */\n | OverlayPositionCoordinate\n /** Update coordinates based on pointer movements on the map, useful for tooltips. */\n | OverlayPositionFollowPointer;\n\n/**\n * Automatically positions the overlay on the mouse cursor's coordinates.\n *\n * This can be used, for example, to implement tooltips for map interactions.\n *\n * @group Map Model\n */\nexport interface OverlayPositionFollowPointer {\n kind: \"follow-pointer\";\n\n /**\n * The initial coordinates.\n *\n * Use `undefined` (the default) to hide until the first mouse event on the map.\n */\n initial?: Coordinate;\n}\n\n/**\n * Places the overlay at the given coordinates.\n *\n * @group Map Model\n */\nexport interface OverlayPositionCoordinate {\n kind: \"coordinate\";\n\n /**\n * The explicit coordinates of the overlay on the map.\n *\n * Using `undefined` hides the overlay.\n */\n coordinate?: Coordinate;\n}\n\n/**\n * Positioning of an overlay relative to its coordinates on the map.\n *\n * @group Map Model\n */\nexport type OverlayPositioning =\n | \"bottom-left\"\n | \"bottom-center\"\n | \"bottom-right\"\n | \"center-left\"\n | \"center-center\"\n | \"center-right\"\n | \"top-left\"\n | \"top-center\"\n | \"top-right\";\n\n/** @group Map Model */\nexport interface OlOverlayOptions extends Omit<Partial<Options>, \"id\" | \"element\"> {}\n\n/**\n * An overlay is an UI element that is displayed over the map.\n *\n * Overlays are tied to coordinates on the map and not to a position on the screen.\n * The overlay renders a react node at the specified coordinates.\n *\n * @group Map Model\n */\nexport class Overlay {\n /**\n * Unique, readonly id of the overlay.\n *\n * Automatically assigned when the overlay is created. Use the `tag` property for custom identifiers.\n */\n readonly id: string;\n\n /**\n * Optional, readonly tag that helps identifying the overlay instance.\n */\n readonly tag: string | undefined;\n\n /**\n * Raw, corresponding OpenLayers overlay object.\n *\n * **warning** Manipulation of the OpenLayers object can create inconsistencies that lead to errors. The OpenLayers API can change with updates of OpenLayers.\n *\n * @see https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html\n */\n readonly olOverlay: OlOverlay;\n\n #parent: Overlays;\n #isDestroyed = reactive(false);\n #position = reactive<OverlayPosition>({ kind: \"coordinate\" });\n #content: Reactive<ReactNode>;\n #overlayDiv: HTMLDivElement;\n #resources: Resource[] = [];\n\n #coordinate = synchronized(\n () => this.olOverlay.getPosition(),\n (cb) => {\n const key = this.olOverlay.on(\"change:position\", cb);\n return () => unByKey(key);\n }\n );\n #positioning = synchronized(\n () => this.olOverlay.getPositioning(),\n (cb) => {\n const key = this.olOverlay.on(\"change:positioning\", cb);\n return () => unByKey(key);\n }\n );\n #offset = synchronized(\n () => this.olOverlay.getOffset(),\n (cb) => {\n const key = this.olOverlay.on(\"change:offset\", cb);\n return () => unByKey(key);\n }\n );\n\n constructor(internalTag: InternalConstructorTag, options: OverlayOptions, parent: Overlays) {\n if (internalTag !== INTERNAL_CONSTRUCTOR_TAG) {\n throw new Error(\"The overlay constructor is private.\");\n }\n const {\n className,\n ariaRole,\n position,\n tag,\n content,\n offset,\n positioning,\n stopEvent,\n advanced\n } = options;\n this.id = uuid4v();\n this.tag = tag;\n this.#overlayDiv = createElement(ariaRole, className);\n\n this.olOverlay = new OlOverlay({\n element: this.#overlayDiv,\n id: this.id,\n offset,\n positioning,\n stopEvent,\n //simply override with advanced OL Options if set\n ...advanced\n });\n this.#parent = parent;\n this.#content = reactive(content);\n this.setPosition(position);\n\n parent[REGISTER_OVERLAY](this);\n\n this.#resources.push(\n // Update coordinate based on pointer movements when configured.\n // Automatically subscribes and unsubscribes on changes.\n watchValue(\n () => this.#position.value?.kind === \"follow-pointer\",\n (followPointer) => {\n if (!followPointer) {\n return;\n }\n\n // NOTE: If this turns out to be unstable we can also transport the map model reference here\n // to get our olMap.\n const olMap = this.olOverlay.getMap();\n if (!olMap) {\n LOG.error(\n `Overlay ${this.olOverlay.getId()} is not registered with a map.`\n );\n return;\n }\n\n const pointerMoveKey: EventsKey = olMap.on(\"pointermove\", (e) => {\n this.olOverlay.setPosition(e.coordinate);\n });\n return () => unByKey(pointerMoveKey);\n },\n { immediate: true, dispatch: \"sync\" }\n )\n );\n }\n\n /**\n * Destroys the overlay and removes it from the map.\n * An overlay that is destroyed cannot be added to the map again.\n */\n destroy(): void {\n if (this.isDestroyed) {\n return;\n }\n\n batch(() => {\n this.#isDestroyed.value = true;\n this.#parent[UNREGISTER_OVERLAY](this);\n this.olOverlay.dispose();\n destroyResources(this.#resources);\n });\n }\n\n /**\n * Indicates if the overlay instance has been destroyed.\n */\n get isDestroyed(): boolean {\n return this.#isDestroyed.value;\n }\n\n /**\n * Current coordinates of the overlay on the map.\n *\n * The coordinates on the map are configured via {@link OverlayOptions.position} or {@link setPosition}.\n *\n * - If configured with static coordinates (i.e. `position.kind === \"coordinate\"`), this is\n * the same as `position.coordinate`.\n * - If configured with `\"follow-pointer\"` position, this is the result of the user's pointer movements.\n */\n get currentCoordinate(): Coordinate | undefined {\n return this.#coordinate.value;\n }\n\n /**\n * The content of the overlay that is currently rendered.\n */\n get content(): ReactNode {\n return this.#content.value;\n }\n\n /**\n * The HTML element that that wraps the overlay's content.\n */\n get element(): HTMLElement {\n return this.#overlayDiv;\n }\n\n /**\n * Offset in _pixels_ relative to the overlay`s coordinates.\n *\n * The first element in the array is the horizontal offset.\n */\n get offset(): number[] {\n return this.#offset.value;\n }\n\n /**\n * The configured position of the overlay on the map.\n *\n * See also {@link currentCoordinate} to get the coordinate\n * that are the result of this configuration.\n *\n * > NOTE: The return value of the getter may not be the same\n * > as the input to the setter (or constructor) due to normalization.\n */\n get position(): OverlayPosition {\n return this.#position.value;\n }\n\n /**\n * Positioning of an overlay relative to its coordinates on the map.\n */\n get positioning(): OverlayPositioning {\n return this.#positioning.value;\n }\n\n /**\n * Set new content that is rendered on the overlay.\n */\n setContent(content: ReactNode): void {\n this.#content.value = content;\n }\n\n /**\n * Set the position of the overlay.\n *\n * This controls the coordinates of the map.\n * The overlay is not rendered if the coordinates are `undefined`.\n *\n * See also {@link currentCoordinate} to get the coordinates\n * that are the result of this configuration.\n *\n * @see {@link OverlayPosition}\n */\n setPosition(position: OverlayOptions[\"position\"]) {\n const normalized = normalizePosition(position);\n\n let newCoordinate: Coordinate | undefined;\n if (normalized) {\n if (normalized.kind === \"coordinate\") {\n newCoordinate = normalized.coordinate;\n } else {\n newCoordinate = normalized.initial;\n // mouse event handler will update this on its own\n }\n }\n\n batch(() => {\n this.#position.value = normalized;\n this.olOverlay.setPosition(newCoordinate);\n });\n }\n\n /**\n * Set offset in _pixels_ relative to the overlay`s coordinates on the map.\n * The first element in the array is the horizontal offset.\n */\n setOffset(offset: number[]) {\n this.olOverlay.setOffset(offset);\n }\n\n /**\n * Set positioning of an overlay relative to its coordinates on the map.\n */\n setPositioning(positioning: OverlayPositioning) {\n this.olOverlay.setPositioning(positioning);\n }\n}\n\nfunction normalizePosition(position: OverlayOptions[\"position\"]): OverlayPosition {\n if (!position || Array.isArray(position)) {\n return { kind: \"coordinate\", coordinate: position };\n }\n if (position === \"follow-pointer\") {\n return { kind: \"follow-pointer\" };\n }\n if (typeof position !== \"object\") {\n throw new Error(\"Unexpected position: \" + position);\n }\n return position;\n}\n\nfunction createElement(ariaRole: string | undefined, classNameProp: string | undefined) {\n const overlayDiv = document.createElement(\"div\");\n if (ariaRole) {\n overlayDiv.role = ariaRole;\n }\n\n let className = \"map-overlay\";\n if (classNameProp) {\n className += ` ${classNameProp}`;\n }\n overlayDiv.className = className;\n return overlayDiv;\n}\n"],"names":["uuid4v","OlOverlay"],"mappings":"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"}
|