@emuanalytics/flow-rdf-core 4.0.3 → 4.0.5

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 (89) hide show
  1. package/README.md +1 -64
  2. package/dist/index.d.mts +36 -31
  3. package/dist/index.d.ts +36 -31
  4. package/dist/index.mjs +20 -3249
  5. package/dist/lib/context/context-registry.mjs +63 -0
  6. package/dist/lib/context/debugger.mjs +240 -0
  7. package/dist/lib/context/flow-context.mjs +61 -0
  8. package/dist/lib/context/global-state.mjs +70 -0
  9. package/dist/lib/context/map-registry.mjs +59 -0
  10. package/dist/lib/context/query-registry.mjs +53 -0
  11. package/dist/lib/errors/flow-error.mjs +10 -0
  12. package/dist/lib/errors/flow-expression-error.mjs +14 -0
  13. package/dist/lib/errors/flow-map-error.mjs +9 -0
  14. package/dist/lib/expressions/expression-parser.mjs +198 -0
  15. package/dist/lib/expressions/functions/from-palette.mjs +75 -0
  16. package/dist/lib/expressions/functions/regex.mjs +25 -0
  17. package/dist/lib/expressions/functions/state.mjs +25 -0
  18. package/dist/lib/expressions/parser-helpers.mjs +37 -0
  19. package/dist/lib/expressions/reactive-expression.mjs +253 -0
  20. package/dist/lib/map/flow-core-map.mjs +749 -0
  21. package/dist/lib/map/plugins/annotations/annotation-layers.mjs +163 -0
  22. package/dist/lib/map/plugins/annotations/annotation.events.mjs +27 -0
  23. package/dist/lib/map/plugins/annotations/annotation.plugin.mjs +498 -0
  24. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/modes/DirectModeOverride.mjs +67 -0
  25. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/modes/DragCircleMode.mjs +65 -0
  26. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/utils/create_supplementary_points_circle.mjs +15 -0
  27. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/utils/drag_pan.mjs +20 -0
  28. package/dist/lib/map/plugins/data-join.plugin.mjs +173 -0
  29. package/dist/lib/map/plugins/export/export.plugin.mjs +21 -0
  30. package/dist/lib/map/plugins/export/map-exporter.mjs +177 -0
  31. package/dist/lib/map/plugins/hover-effect.plugin.mjs +58 -0
  32. package/dist/lib/map/plugins/index.d.mts +37 -72
  33. package/dist/lib/map/plugins/index.d.ts +37 -72
  34. package/dist/lib/map/plugins/index.mjs +11 -1811
  35. package/dist/lib/map/plugins/keyboard-shortcut-manager.mjs +120 -0
  36. package/dist/lib/map/plugins/map-plugin-base.mjs +25 -0
  37. package/dist/lib/map/plugins/plugin-manager.mjs +135 -0
  38. package/dist/lib/map/plugins/popup.plugin.mjs +55 -0
  39. package/dist/lib/map/plugins/selection/selection.events.mjs +21 -0
  40. package/dist/lib/map/plugins/selection/selection.plugin.mjs +136 -0
  41. package/dist/lib/map/plugins/selection/source-selection.mjs +156 -0
  42. package/dist/lib/map/plugins/url-sync.plugin.mjs +55 -0
  43. package/dist/lib/map/support/image-registry.mjs +82 -0
  44. package/dist/lib/map/support/map-events.mjs +71 -0
  45. package/dist/lib/map/support/map-feature-stream.mjs +158 -0
  46. package/dist/lib/map/support/map-popup.mjs +159 -0
  47. package/dist/lib/map/types.mjs +7 -0
  48. package/dist/lib/map-style/map-data-source.mjs +192 -0
  49. package/dist/lib/map-style/map-layer-style-builder-generated.mjs +1307 -0
  50. package/dist/lib/map-style/map-layer-style-builder.mjs +86 -0
  51. package/dist/lib/map-style/map-layer.mjs +223 -0
  52. package/dist/lib/map-style/map-style.mjs +178 -0
  53. package/dist/lib/queries/async-committer.mjs +30 -0
  54. package/dist/lib/queries/query.mjs +172 -0
  55. package/dist/lib/state-store/decorators.mjs +83 -0
  56. package/dist/lib/state-store/state-store.mjs +534 -0
  57. package/dist/lib/state-store/utils.mjs +7 -0
  58. package/dist/lib/utils/announce.mjs +12 -0
  59. package/dist/lib/utils/assert.mjs +12 -0
  60. package/dist/{shared/flow-rdf-core.187cb345.mjs → lib/utils/debounce.mjs} +3 -39
  61. package/dist/lib/utils/decorators.mjs +59 -0
  62. package/dist/lib/utils/deferred.mjs +11 -0
  63. package/dist/lib/utils/ensure-array.mjs +16 -0
  64. package/dist/{shared/flow-rdf-core.1f0901c5.mjs → lib/utils/feature-type-checks.mjs} +2 -2
  65. package/dist/lib/utils/functional.mjs +22 -0
  66. package/dist/lib/utils/global.mjs +18 -0
  67. package/dist/lib/utils/index.mjs +8 -5
  68. package/dist/lib/utils/random-id.mjs +9 -0
  69. package/dist/lib/utils/string-utils.mjs +3 -0
  70. package/dist/lib/utils/throttle.mjs +20 -0
  71. package/dist/{shared/flow-rdf-core.25e5f6d7.mjs → lib/utils/type-checks.mjs} +1 -26
  72. package/dist/lib/utils/watchable-promise.mjs +55 -0
  73. package/dist/package.json.mjs +3 -0
  74. package/dist/shared/{flow-rdf-core.4dde996e.d.cts → flow-rdf-core.8b5acf14.d.mts} +1315 -172
  75. package/dist/shared/{flow-rdf-core.4dde996e.d.ts → flow-rdf-core.8b5acf14.d.ts} +1315 -172
  76. package/package.json +4 -8
  77. package/dist/index.cjs +0 -3316
  78. package/dist/index.d.cts +0 -90
  79. package/dist/lib/map/plugins/index.cjs +0 -1851
  80. package/dist/lib/map/plugins/index.d.cts +0 -345
  81. package/dist/lib/utils/index.cjs +0 -48
  82. package/dist/lib/utils/index.d.cts +0 -160
  83. package/dist/shared/flow-rdf-core.06e85a6c.cjs +0 -1394
  84. package/dist/shared/flow-rdf-core.4dde996e.d.mts +0 -1916
  85. package/dist/shared/flow-rdf-core.55c169ca.cjs +0 -150
  86. package/dist/shared/flow-rdf-core.63162669.d.cts +0 -10
  87. package/dist/shared/flow-rdf-core.65045caf.mjs +0 -1360
  88. package/dist/shared/flow-rdf-core.a82b9be4.cjs +0 -34
  89. package/dist/shared/flow-rdf-core.f50908f0.cjs +0 -102
@@ -0,0 +1,55 @@
1
+ import { MapPluginBase } from './map-plugin-base.mjs';
2
+ import Debug from 'debug';
3
+
4
+ var __defProp = Object.defineProperty;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __publicField = (obj, key, value) => {
7
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
+ return value;
9
+ };
10
+ const debug = Debug("flow:url-sync-plugin");
11
+ class UrlSyncPlugin extends MapPluginBase {
12
+ constructor(pluginManager) {
13
+ super(pluginManager);
14
+ __publicField(this, "name", "UrlSyncPlugin");
15
+ }
16
+ initialize() {
17
+ const searchParams = new URLSearchParams(window.location.search);
18
+ const hash = searchParams.get(this.map.id);
19
+ if (hash) {
20
+ const center = this.hashToMapState(hash);
21
+ debug("Setting map position from URL", center);
22
+ this.map.setCenter(center);
23
+ }
24
+ }
25
+ handleMoveEnd(event) {
26
+ const center = this.mapStateToHash(this.map.getCenter());
27
+ const searchParams = new URLSearchParams(window.location.search);
28
+ searchParams.set(this.map.id, center);
29
+ const newUrl = `${location.pathname}?${searchParams.toString()}`;
30
+ debug("Updating URL with map position", center);
31
+ window.history.replaceState({}, "", newUrl);
32
+ }
33
+ mapStateToHash(mapCenter) {
34
+ const state = {
35
+ z: mapCenter.zoom.toFixed(3),
36
+ x: mapCenter.lng.toFixed(3),
37
+ y: mapCenter.lat.toFixed(3),
38
+ pitch: mapCenter.pitch.toFixed(1),
39
+ bearing: mapCenter.bearing.toFixed(1)
40
+ };
41
+ return `${state.z}_${state.x}_${state.y}_${state.pitch}_${state.bearing}`;
42
+ }
43
+ hashToMapState(hash) {
44
+ const [zoom, x, y, pitch, bearing] = hash.split("_");
45
+ return {
46
+ lng: +x,
47
+ lat: +y,
48
+ zoom: +zoom,
49
+ pitch: +pitch,
50
+ bearing: +bearing
51
+ };
52
+ }
53
+ }
54
+
55
+ export { UrlSyncPlugin };
@@ -0,0 +1,82 @@
1
+ import Debug from 'debug';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5
+ var __publicField = (obj, key, value) => {
6
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
+ return value;
8
+ };
9
+ Debug("flow:image-registry");
10
+ const unknownImageSVG = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='flowicon'%3E%3C!--! Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--%3E%3Cpath d='M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256 256-114.6 256-256S397.4 0 256 0zm0 400c-18 0-32-14-32-32s13.1-32 32-32c17.1 0 32 14 32 32s-14.9 32-32 32zm69.1-142L280 286v2c0 13-11 24-24 24s-24-11-24-24v-16c0-8 4-16 12-21l57-34c7-4 11-11 11-19 0-12-10.9-22-22.9-22H238c-12.9 0-22 10-22 22 0 13-11 24-24 24s-24-11-24-24c0-39 31-70 69.1-70h51.1c40.8 0 71.8 31 71.8 70 0 24-13 47-34.9 60z'/%3E%3C/svg%3E`;
11
+ class ImageRegistry {
12
+ constructor() {
13
+ __publicField(this, "_registry", /* @__PURE__ */ new Map());
14
+ __publicField(this, "_unknownImage", null);
15
+ }
16
+ get unknownImage() {
17
+ if (!this._unknownImage) {
18
+ const image = new Image(40, 40);
19
+ image.src = unknownImageSVG;
20
+ this._unknownImage = {
21
+ id: "unknown-image",
22
+ src: unknownImageSVG,
23
+ pixelDensity: 2,
24
+ image
25
+ };
26
+ }
27
+ return this._unknownImage;
28
+ }
29
+ /**
30
+ * Register a map icon image.
31
+ *
32
+ * @param id Image ID.
33
+ * @param src Image source URL.
34
+ * @param width Image display width.
35
+ * @param height Image display height.
36
+ * @param pixelDensity Image pixel density. Defaults to `2` - the source image should be @2x resolution to enable better quality rendering on high-resolution displays.
37
+ * @param recolor Set to `true` to allow recoloring of map icon image using map layer style properties.
38
+ */
39
+ registerImage(id, src, width, height, pixelDensity = 2, recolor = false) {
40
+ const entry = { id, src, width, height, pixelDensity, recolor };
41
+ this._registry.set(id, entry);
42
+ return entry;
43
+ }
44
+ /**
45
+ * Get an image registry entry.
46
+ *
47
+ * @param id Image ID.
48
+ * @returns The image registry entry.
49
+ */
50
+ getImage(id) {
51
+ const registryEntry = this._registry.get(id);
52
+ if (!registryEntry) {
53
+ return this.unknownImage;
54
+ }
55
+ if (!registryEntry.image) {
56
+ registryEntry.image = this.loadImage(
57
+ registryEntry.src,
58
+ registryEntry.width,
59
+ registryEntry.height,
60
+ registryEntry.pixelDensity
61
+ );
62
+ }
63
+ return registryEntry;
64
+ }
65
+ /**
66
+ *
67
+ * @param src Image source URL.
68
+ * @param width Image display width in pixels.
69
+ * @param height Image display height in pixels.
70
+ * @param pixelDensity Image pixel density. Defaults to `2` - the source image should be @2x resolution to enable better quality rendering on high-resolution displays.
71
+ */
72
+ loadImage(src, width, height, pixelDensity = 2) {
73
+ const image = new Image();
74
+ image.crossOrigin = "Anonymous";
75
+ image.width = width ? width * pixelDensity : image.width;
76
+ image.height = height ? height * pixelDensity : image.height;
77
+ image.src = src;
78
+ return image;
79
+ }
80
+ }
81
+
82
+ export { ImageRegistry };
@@ -0,0 +1,71 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ class MapEvent {
8
+ constructor(type, map, originalEvent) {
9
+ __publicField(this, "type");
10
+ __publicField(this, "map");
11
+ __publicField(this, "originalEvent");
12
+ this.type = type;
13
+ this.map = map;
14
+ this.originalEvent = originalEvent;
15
+ }
16
+ static fromMaplibreEvent(type, map, maplibreEvent) {
17
+ return new MapEvent(type, map, maplibreEvent.originalEvent);
18
+ }
19
+ }
20
+ class MapMouseEvent extends MapEvent {
21
+ constructor(type, map, point, lngLat, features, originalEvent) {
22
+ super(type, map, originalEvent);
23
+ /**
24
+ * The pixel coordinates of the mouse cursor, relative to the map and measured from the top left corner.
25
+ */
26
+ __publicField(this, "point");
27
+ /**
28
+ * The geographic location on the map of the mouse cursor.
29
+ */
30
+ __publicField(this, "lngLat");
31
+ __publicField(this, "features");
32
+ this.point = point;
33
+ this.lngLat = lngLat;
34
+ this.features = features;
35
+ }
36
+ static fromMaplibreMouseEvent(type, maplibreMouseEvent, map, features) {
37
+ return new MapMouseEvent(
38
+ type,
39
+ map,
40
+ [maplibreMouseEvent.point.x, maplibreMouseEvent.point.y],
41
+ [maplibreMouseEvent.lngLat.lng, maplibreMouseEvent.lngLat.lat],
42
+ features,
43
+ maplibreMouseEvent.originalEvent
44
+ );
45
+ }
46
+ }
47
+ class MapSourceEvent extends MapEvent {
48
+ constructor(type, map, source) {
49
+ super(type, map);
50
+ __publicField(this, "source");
51
+ this.source = source;
52
+ }
53
+ }
54
+ class MapLoadingEvent extends MapEvent {
55
+ constructor(map, loading) {
56
+ super("loading", map);
57
+ __publicField(this, "loading");
58
+ this.loading = loading;
59
+ }
60
+ }
61
+ class MapStyleChangeEvent extends MapEvent {
62
+ constructor(type, map, oldStyle, newStyle) {
63
+ super(type, map);
64
+ __publicField(this, "oldStyle");
65
+ __publicField(this, "newStyle");
66
+ this.oldStyle = oldStyle;
67
+ this.newStyle = newStyle;
68
+ }
69
+ }
70
+
71
+ export { MapEvent, MapLoadingEvent, MapMouseEvent, MapSourceEvent, MapStyleChangeEvent };
@@ -0,0 +1,158 @@
1
+ import Debug from 'debug';
2
+ import { makeObservable, observable, computed, onBecomeObserved, onBecomeUnobserved, runInAction } from 'mobx';
3
+ import { toStream } from 'mobx-utils';
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __publicField = (obj, key, value) => {
8
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
9
+ return value;
10
+ };
11
+ Debug("flow:map-feature-stream");
12
+ class MapFeatureStream {
13
+ constructor(options) {
14
+ __publicField(this, "_boundHandleLoading");
15
+ __publicField(this, "_boundHandleSourceFeatureState");
16
+ __publicField(this, "_options");
17
+ __publicField(this, "_sourceLoadCount", 0);
18
+ __publicField(this, "_sourceLoaded", true);
19
+ var _a;
20
+ this._options = {
21
+ fireImmediately: true,
22
+ ...options
23
+ };
24
+ const sourceType = options.map.getSource(options.source).type;
25
+ if (sourceType === "vector")
26
+ (_a = this._options).sourceLayer ?? (_a.sourceLayer = "geometry");
27
+ makeObservable(this, {
28
+ _options: observable,
29
+ _sourceLoadCount: observable,
30
+ featureData: computed.struct
31
+ });
32
+ this._boundHandleLoading = this.handleLoading.bind(this);
33
+ this._boundHandleSourceFeatureState = this.handleSourceFeatureState.bind(this);
34
+ onBecomeObserved(this, "featureData", this.resume.bind(this));
35
+ onBecomeUnobserved(this, "featureData", this.suspend.bind(this));
36
+ }
37
+ /**
38
+ * Returns feature data corresponding to the requested feature IDs. This is a computed property that will
39
+ * automatically update when the feature data changes. Accessing this property within a reactive
40
+ * context will automatically trigger a reactive update.
41
+ *
42
+ * :::info
43
+ * This method provides an alternative to {@link subscribe} for responding to feature data upates.
44
+ * :::
45
+ *
46
+ * @example
47
+ * ```js
48
+ * const featureStream = myMap.featureStream({
49
+ * featureIds: ['feature1', 'feature2'],
50
+ * source: 'my-source'
51
+ * });
52
+ *
53
+ * const disposer = appState.autoRun(() => {
54
+ * const featureData = featureStream.featureData;
55
+ * console.log('Feature data changed:', featureData);
56
+ * });
57
+ * ...
58
+ * disposer();
59
+ * ```
60
+ *
61
+ */
62
+ get featureData() {
63
+ this._sourceLoadCount;
64
+ const featureData = this.queryFeatureData(this._options.featureIds);
65
+ return featureData;
66
+ }
67
+ /** Returns the feature IDs being tracked. */
68
+ get featureIds() {
69
+ return this._options.featureIds;
70
+ }
71
+ /** Update the feature IDs being tracked. */
72
+ set featureIds(featureIds) {
73
+ runInAction(() => {
74
+ this._options.featureIds = featureIds;
75
+ });
76
+ }
77
+ /**
78
+ * Subscribe to the feature stream. The supplied handler will be called whenever the feature data changes.
79
+ *
80
+ * :::warning
81
+ * Subscriptions should be disposed of when no longer required by calling their `unsubscribe()` method.
82
+ * :::
83
+ */
84
+ subscribe(handler) {
85
+ const mobxSubscription = toStream(() => this.featureData, this._options.fireImmediately).subscribe(handler);
86
+ return {
87
+ unsubscribe: () => {
88
+ mobxSubscription.unsubscribe();
89
+ }
90
+ };
91
+ }
92
+ featureFromMaplibreFeature(feature) {
93
+ return {
94
+ id: feature.id,
95
+ geometry: feature.geometry,
96
+ source: this._options.source,
97
+ sourceLayer: this._options.sourceLayer,
98
+ properties: feature.properties,
99
+ state: this._options.map.maplibreMap.getFeatureState({
100
+ id: feature.id,
101
+ source: this._options.source,
102
+ sourceLayer: this._options.sourceLayer
103
+ })
104
+ };
105
+ }
106
+ handleLoading(event) {
107
+ let loaded = false;
108
+ if (event.type === "sourcedata" && event.sourceId === this._options.source) {
109
+ loaded = event.isSourceLoaded;
110
+ } else if (event.type === "idle") {
111
+ loaded = true;
112
+ }
113
+ if (this._sourceLoaded !== loaded) {
114
+ this._sourceLoaded = loaded;
115
+ if (loaded) {
116
+ runInAction(() => {
117
+ this._sourceLoadCount++;
118
+ });
119
+ }
120
+ }
121
+ }
122
+ handleSourceFeatureState(event) {
123
+ if (event.type === "sourceFeatureState" && event.source === this._options.source) {
124
+ runInAction(() => {
125
+ this._sourceLoadCount++;
126
+ });
127
+ }
128
+ }
129
+ queryFeatureData(featureIDs) {
130
+ if (featureIDs.length === 0) {
131
+ return {};
132
+ }
133
+ const featureIdProp = this._options.map.getSource(this._options.source).featureId;
134
+ let features = this._options.map.maplibreMap.querySourceFeatures(this._options.source, {
135
+ sourceLayer: this._options.sourceLayer,
136
+ filter: ["in", ["get", featureIdProp], ["literal", featureIDs]]
137
+ });
138
+ const ids = /* @__PURE__ */ new Set();
139
+ features = features.filter((feature) => ids.has(feature.id) ? false : ids.add(feature.id) && true);
140
+ const featureData = features.reduce((accum, f) => {
141
+ accum[f.id] = this.featureFromMaplibreFeature(f);
142
+ return accum;
143
+ }, {});
144
+ return featureData;
145
+ }
146
+ resume() {
147
+ this._options.map.maplibreMap.on("sourcedata", this._boundHandleLoading);
148
+ this._options.map.maplibreMap.on("idle", this._boundHandleLoading);
149
+ this._options.map.on("sourceFeatureState", this._boundHandleSourceFeatureState);
150
+ }
151
+ suspend() {
152
+ this._options.map.maplibreMap.off("sourcedata", this._boundHandleLoading);
153
+ this._options.map.maplibreMap.off("idle", this._boundHandleLoading);
154
+ this._options.map.off("sourceFeatureState", this._boundHandleSourceFeatureState);
155
+ }
156
+ }
157
+
158
+ export { MapFeatureStream };
@@ -0,0 +1,159 @@
1
+ import maplibre from '@emuanalytics/maplibre-gl';
2
+ import Debug from 'debug';
3
+ import EventEmitter from 'eventemitter3';
4
+ import * as lit from 'lit-html';
5
+ import { assert } from '../../utils/assert.mjs';
6
+ import { isArray, isStringFull, isFunction, isString } from '../../utils/type-checks.mjs';
7
+ import { isFeatureWithId } from '../types.mjs';
8
+ import { MapFeatureStream } from './map-feature-stream.mjs';
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __publicField = (obj, key, value) => {
13
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
14
+ return value;
15
+ };
16
+ Debug("flow:map-popup");
17
+ class MapPopup extends EventEmitter {
18
+ /**
19
+ * Constructs a new `MapPopup` instance.
20
+ *
21
+ * This is called by the `FlowMap::openPopup` method.
22
+ *
23
+ * @param map Parent Flo.w map.
24
+ * @param options Popup options.
25
+ */
26
+ constructor(map, options) {
27
+ super();
28
+ this.map = map;
29
+ this.options = options;
30
+ __publicField(this, "_feature");
31
+ __publicField(this, "_contentContainer");
32
+ __publicField(this, "_featureStream", null);
33
+ //private _featureStreamSubscription: ISubscription | null = null;
34
+ __publicField(this, "_maplibrePopup", null);
35
+ __publicField(this, "_featureStreamDisposer");
36
+ this.options = {
37
+ // Defaults
38
+ closeButton: true,
39
+ closeOnClick: false,
40
+ closeOnMove: false,
41
+ maxWidth: "300px",
42
+ trackFeature: true,
43
+ //
44
+ ...this.options
45
+ };
46
+ }
47
+ get feature() {
48
+ return this._feature;
49
+ }
50
+ /**
51
+ * Close the popup.
52
+ */
53
+ close() {
54
+ if (this._maplibrePopup) {
55
+ this._maplibrePopup.remove();
56
+ this._maplibrePopup = null;
57
+ }
58
+ }
59
+ /**
60
+ * Move the popup to a new location.
61
+ *
62
+ * @param lngLat New location.
63
+ */
64
+ moveTo(lngLat) {
65
+ this._maplibrePopup.setLngLat(lngLat);
66
+ }
67
+ open(eventOrLngLat, feature) {
68
+ if (this._maplibrePopup) {
69
+ return;
70
+ }
71
+ if (!isArray(eventOrLngLat)) {
72
+ if (isFeatureWithId(eventOrLngLat.features[0])) {
73
+ feature = eventOrLngLat.features[0];
74
+ }
75
+ eventOrLngLat = eventOrLngLat.lngLat;
76
+ }
77
+ if (feature) {
78
+ assert(isFeatureWithId(feature), "MapPopup.open(): feature must have unique ID");
79
+ }
80
+ this._maplibrePopup = new maplibre.Popup({
81
+ className: this.cssClasses().join(" "),
82
+ closeButton: this.options.closeButton,
83
+ closeOnClick: this.options.closeOnClick,
84
+ closeOnMove: this.options.closeOnMove,
85
+ maxWidth: this.options.maxWidth
86
+ });
87
+ this._maplibrePopup.once("close", this.popupCloseHandler.bind(this));
88
+ this._contentContainer = document.createElement("div");
89
+ this._contentContainer.classList.add("flow-map-popup-content");
90
+ this._maplibrePopup.setLngLat(eventOrLngLat).setDOMContent(this._contentContainer).addTo(this.map.maplibreMap);
91
+ if (feature) {
92
+ this._feature = feature;
93
+ this._featureStream = new MapFeatureStream({
94
+ map: this.map,
95
+ source: feature.source,
96
+ sourceLayer: feature.sourceLayer,
97
+ featureIds: [feature.id]
98
+ });
99
+ this._featureStreamDisposer = this.map.context.state.autorun(() => {
100
+ const data = this._featureStream?.featureData;
101
+ if (data) {
102
+ this.handleFeatureUpdate(data[feature.id]);
103
+ }
104
+ });
105
+ } else {
106
+ this.moveTo(eventOrLngLat);
107
+ this.renderContent(null);
108
+ }
109
+ }
110
+ cssClasses() {
111
+ const classes = ["flow-map-popup"];
112
+ if (isStringFull(this.options.class)) {
113
+ classes.push(this.options.class);
114
+ }
115
+ if (this.options.closeButton) {
116
+ classes.push("flow-map-popup--with-close");
117
+ }
118
+ return classes;
119
+ }
120
+ handleFeatureUpdate(feature) {
121
+ if (!feature) {
122
+ this.close();
123
+ return;
124
+ }
125
+ if (this.options.trackFeature) {
126
+ switch (feature.geometry.type) {
127
+ case "Point":
128
+ this.moveTo(feature.geometry.coordinates);
129
+ break;
130
+ case "MultiPoint":
131
+ this.moveTo(feature.geometry.coordinates[0]);
132
+ break;
133
+ }
134
+ }
135
+ this.renderContent(feature);
136
+ }
137
+ popupCloseHandler() {
138
+ if (this._featureStreamDisposer) {
139
+ this._featureStreamDisposer();
140
+ this._featureStreamDisposer = void 0;
141
+ }
142
+ this.emit("closed", this);
143
+ this.removeAllListeners();
144
+ }
145
+ renderContent(feature) {
146
+ const state = this.map.context.state;
147
+ const content = isFunction(this.options.content) ? this.options.content(feature, state) : this.options.content;
148
+ if (isString(content)) {
149
+ this._contentContainer.innerHTML = content;
150
+ } else if (content instanceof Node) {
151
+ this._contentContainer.innerHTML = "";
152
+ this._contentContainer.appendChild(content);
153
+ } else {
154
+ lit.render(content, this._contentContainer);
155
+ }
156
+ }
157
+ }
158
+
159
+ export { MapPopup };
@@ -0,0 +1,7 @@
1
+ import { isDefined } from '../utils/type-checks.mjs';
2
+
3
+ function isFeatureWithId(f) {
4
+ return isDefined(f) && isDefined(f.source) && isDefined(f.id);
5
+ }
6
+
7
+ export { isFeatureWithId };