diff --git a/docs/examples/popup.vue b/docs/examples/popup.vue
new file mode 100644
index 0000000..c1ceef5
--- /dev/null
+++ b/docs/examples/popup.vue
@@ -0,0 +1,42 @@
+// Popup
+//
+// A map with a marker and a popup
+
+
+
+
+
+ Hello
+ HTML content
+
+
+
+
+
+
+
+
diff --git a/lib/components/index.ts b/lib/components/index.ts
index df391b1..9b9de6d 100644
--- a/lib/components/index.ts
+++ b/lib/components/index.ts
@@ -10,6 +10,7 @@ export { default as MglScaleControl } from './controls/scale.control';
export { default as MglStyleSwitchControl } from './controls/styleSwitch.control';
export { default as MglButton } from './button.component';
export { default as MglMarker } from './marker.component';
+export { default as MglPopup } from './popup.component';
export { default as MglCanvasSource } from './sources/canvas.source';
export { default as MglGeoJsonSource } from './sources/geojson.source';
export { default as MglImageSource } from './sources/image.source';
diff --git a/lib/components/marker.component.ts b/lib/components/marker.component.ts
index 31e08f4..b3db292 100644
--- a/lib/components/marker.component.ts
+++ b/lib/components/marker.component.ts
@@ -1,7 +1,7 @@
-import { defineComponent, inject, onBeforeUnmount, type PropType, unref, watch } from 'vue';
+import { defineComponent, inject, provide, onBeforeUnmount, type PropType, unref, watch, shallowRef, h } from 'vue';
import { type LngLatLike, Marker, type MarkerOptions, type PointLike, type PositionAnchor } from 'maplibre-gl';
import { MapLib } from '@/lib/lib/map.lib';
-import { mapSymbol } from '@/lib/types';
+import { mapSymbol, markerSymbol } from '@/lib/types';
export default /*#__PURE__*/ defineComponent({
name : 'MglMarker',
@@ -20,7 +20,7 @@ export default /*#__PURE__*/ defineComponent({
pitchAlignment : String as PropType<'map' | 'viewport' | 'auto'>,
scale : Number as PropType
},
- setup(props) {
+ setup(props, { slots }) {
const map = inject(mapSymbol)!,
opts: MarkerOptions = Object.keys(props)
@@ -32,6 +32,7 @@ export default /*#__PURE__*/ defineComponent({
const marker = new Marker(opts);
marker.setLngLat(props.coordinates).addTo(map.value!);
+ provide(markerSymbol, shallowRef(marker));
watch(() => props.coordinates, v => marker.setLngLat(v));
// watch(() => props.draggable, v => marker.setDraggable(v || false));
@@ -41,10 +42,8 @@ export default /*#__PURE__*/ defineComponent({
onBeforeUnmount(marker.remove.bind(marker));
- return { marker };
-
- },
- render() {
- // nothing
+ return () => [
+ h('div', slots.default ? slots.default({}) : undefined)
+ ];
}
});
diff --git a/lib/components/popup.component.ts b/lib/components/popup.component.ts
new file mode 100644
index 0000000..8305a26
--- /dev/null
+++ b/lib/components/popup.component.ts
@@ -0,0 +1,97 @@
+import { defineComponent, inject, onMounted, onBeforeUnmount, PropType, unref, watch, ref, h } from 'vue';
+import { LngLatLike, Popup, Offset, PositionAnchor, PopupOptions, PointLike } from 'maplibre-gl';
+import { MapLib } from '@/lib/lib/map.lib';
+import { mapSymbol, markerSymbol } from '@/lib/types';
+
+export default /*#__PURE__*/ defineComponent({
+ name : 'MglPopup',
+ emits: ['open', 'close'],
+ props: {
+ coordinates: {
+ type: [ Object, Array ] as unknown as PropType,
+ required: false
+ },
+ closeButton: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ closeOnClick: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ closeOnMove: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ focusAfterOpen: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ anchor: {
+ type: String as PropType,
+ required: false
+ },
+ offset: {
+ type: [Number, Object, Array] as PropType,
+ required: false,
+ },
+ className: {
+ type: String,
+ required: false,
+ },
+ maxWidth: {
+ type: String,
+ default: '240px',
+ },
+ text: {
+ type: String,
+ required: false
+ }
+ },
+ setup(props, { slots, emit }) {
+ const map = inject(mapSymbol);
+ const marker = inject(markerSymbol);
+ const root = ref();
+
+ const opts: PopupOptions = Object.keys(props)
+ .filter(opt => (props as any)[ opt ] !== undefined && MapLib.POPUP_OPTION_KEYS.indexOf(opt as keyof PopupOptions) !== -1)
+ .reduce((obj, opt) => {
+ (obj as any)[ opt ] = unref((props as any)[ opt ]);
+ return obj;
+ }, {});
+
+ const popup = new Popup(opts);
+
+ if (marker && marker.value) {
+ marker.value.setPopup(popup);
+ } else if (props.coordinates && map) {
+ popup.setLngLat(props.coordinates).addTo(map.value!);
+ }
+
+ if (props.text) {
+ popup.setText(props.text);
+ }
+
+ popup.on('open', () => emit('open'));
+ popup.on('close', () => emit('close'));
+
+ watch(() => props.coordinates, (v) => { if (v) { popup.setLngLat(v) } });
+ watch(() => props.text, v => popup.setText(v || ''));
+ watch(() => props.offset, v => popup.setOffset(v));
+ watch(() => props.maxWidth, v => popup.setMaxWidth(v));
+
+ onMounted(() => {
+ if (root.value && !props.text) {
+ popup.setDOMContent(root.value!);
+ }
+ });
+
+ return () => [
+ h('div', {ref: root}, slots.default ? slots.default() : undefined)
+ ];
+ },
+});
diff --git a/lib/lib/map.lib.ts b/lib/lib/map.lib.ts
index 3cb3804..ddc8dc2 100644
--- a/lib/lib/map.lib.ts
+++ b/lib/lib/map.lib.ts
@@ -1,4 +1,4 @@
-import type { Map, MapOptions, MarkerOptions } from 'maplibre-gl';
+import type { Map, MapOptions, MarkerOptions, PopupOptions } from 'maplibre-gl';
import type { MglMap } from '@/lib/components';
import type { MglEvent } from '@/lib/types';
@@ -19,6 +19,10 @@ export class MapLib {
'element', 'offset', 'anchor', 'color', 'draggable', 'clickTolerance', 'rotation', 'rotationAlignment', 'pitchAlignment', 'scale'
];
+ static readonly POPUP_OPTION_KEYS: Array = [
+ 'closeButton', 'closeOnClick', 'closeOnMove', 'focusAfterOpen', 'anchor', 'offset', 'className', 'maxWidth'
+ ];
+
static readonly MAP_EVENT_TYPES = [
'error', 'load', 'idle', 'remove', 'render', 'resize', 'webglcontextlost', 'webglcontextrestored', 'dataloading', 'data', 'tiledataloading',
'sourcedataloading', 'styledataloading', 'sourcedata', 'styledata', 'boxzoomcancel', 'boxzoomstart', 'boxzoomend', 'touchcancel', 'touchmove',
diff --git a/lib/types.ts b/lib/types.ts
index d8d3bef..763c107 100644
--- a/lib/types.ts
+++ b/lib/types.ts
@@ -1,5 +1,5 @@
import type { InjectionKey, Ref, ShallowRef } from 'vue';
-import type { Map, SourceSpecification, StyleSpecification } from 'maplibre-gl';
+import type { Map, Marker, SourceSpecification, StyleSpecification } from 'maplibre-gl';
import type { MglMap } from '@/lib/components';
import type { Emitter } from 'mitt';
import type { SourceLayerRegistry } from '@/lib/lib/sourceLayer.registry';
@@ -10,7 +10,8 @@ export const mapSymbol = Symbol('map') as InjectionKey,
sourceIdSymbol = Symbol('sourceId') as InjectionKey,
sourceLayerRegistry = Symbol('sourceLayerRegistry') as InjectionKey,
- emitterSymbol = Symbol('emitter') as InjectionKey>;
+ emitterSymbol = Symbol('emitter') as InjectionKey>,
+ markerSymbol = Symbol('marker') as InjectionKey>;
export interface MglEvent {
type: string;