Skip to content

Commit

Permalink
Merge branch 'popup'.
Browse files Browse the repository at this point in the history
  • Loading branch information
francois2metz committed Apr 23, 2024
2 parents c1658d3 + 2da86dd commit 43f4284
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 11 deletions.
42 changes: 42 additions & 0 deletions docs/examples/popup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Popup
//
// A map with a marker and a popup
<template>
<mgl-map
:map-style="style"
:center="center"
:zoom="zoom"
>
<mgl-navigation-control />
<mgl-marker :coordinates="coordinates" color="#cc0000">
<mgl-popup>
<h1>Hello</h1>
<p>HTML content</p>
</mgl-popup>
</mgl-marker>
</mgl-map>
</template>

<script setup>
import {
MglMap,
MglNavigationControl,
MglMarker,
MglPopup,
} from 'vue-maplibre-gl';
const style = 'https://api.maptiler.com/maps/streets/style.json?key=cQX2iET1gmOW38bedbUh';
const center = [12.550343, 55.665957];
const zoom = 8;
const coordinates = [12.550343, 55.665957];
</script>

<style lang="scss">
@import "maplibre-gl/dist/maplibre-gl.css";
@import "vue-maplibre-gl/dist/vue-maplibre-gl.css";
body {
margin: 0;
}
html, body, #app { height: 100%; }
</style>
1 change: 1 addition & 0 deletions lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
15 changes: 7 additions & 8 deletions lib/components/marker.component.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -20,7 +20,7 @@ export default /*#__PURE__*/ defineComponent({
pitchAlignment : String as PropType<'map' | 'viewport' | 'auto'>,
scale : Number as PropType<number>
},
setup(props) {
setup(props, { slots }) {

const map = inject(mapSymbol)!,
opts: MarkerOptions = Object.keys(props)
Expand All @@ -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));
Expand All @@ -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)
];
}
});
97 changes: 97 additions & 0 deletions lib/components/popup.component.ts
Original file line number Diff line number Diff line change
@@ -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<LngLatLike>,
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<PositionAnchor>,
required: false
},
offset: {
type: [Number, Object, Array] as PropType<Offset>,
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)
];
},
});
6 changes: 5 additions & 1 deletion lib/lib/map.lib.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -19,6 +19,10 @@ export class MapLib {
'element', 'offset', 'anchor', 'color', 'draggable', 'clickTolerance', 'rotation', 'rotationAlignment', 'pitchAlignment', 'scale'
];

static readonly POPUP_OPTION_KEYS: Array<keyof PopupOptions> = [
'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',
Expand Down
5 changes: 3 additions & 2 deletions lib/types.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -10,7 +10,8 @@ export const mapSymbol = Symbol('map') as InjectionKey<ShallowRef<Map
componentIdSymbol = Symbol('componentId') as InjectionKey<number>,
sourceIdSymbol = Symbol('sourceId') as InjectionKey<string>,
sourceLayerRegistry = Symbol('sourceLayerRegistry') as InjectionKey<SourceLayerRegistry>,
emitterSymbol = Symbol('emitter') as InjectionKey<Emitter<MglEvents>>;
emitterSymbol = Symbol('emitter') as InjectionKey<Emitter<MglEvents>>,
markerSymbol = Symbol('marker') as InjectionKey<ShallowRef<Marker | undefined>>;

export interface MglEvent<T = any> {
type: string;
Expand Down

0 comments on commit 43f4284

Please sign in to comment.