VMap
Usage
<script setup lang="ts">
import { VMap } from '@geoql/v-maplibre';
import type { MapOptions } from 'maplibre-gl';
const mapOptions: MapOptions = {
style: 'https://demotiles.maplibre.org/style.json',
center: [-74.5, 40],
zoom: 9,
};
const handleMapLoad = (map) => {
console.log('Map loaded!', map);
};
</script>
<template>
<VMap
:options="mapOptions"
@loaded="handleMapLoad"
style="height: 500px"
></VMap>
</template>
Props
options
- Type:
MapOptions - Required:
true - Default:
{ container: 'map' }
MapLibre GL map options. See MapLibre GL documentation for all available options.
Common options include:
style: URL to the map style or a style objectcenter: Initial map center[lng, lat]zoom: Initial zoom levelbearing: Initial bearing (rotation)pitch: Initial pitch (tilt)minZoom: Minimum zoom levelmaxZoom: Maximum zoom levelmaxBounds: Map bounds constraint
supportPmtiles
- Type:
boolean - Required:
false - Default:
false
Enable PMTiles protocol support. Set to true if you plan to use PMTiles layers.
<VMap :options="mapOptions" support-pmtiles></VMap>
globalState
- Type:
Record<string, unknown> - Required:
false - Default:
undefined
Reactive values for global-state expressions in the style. The object is the initial state (it overrides the defaults in the style's state property and takes precedence over options.globalState). After the map is created, each changed key calls map.setGlobalStateProperty, and a removed key resets to the style default. Nested changes (an array item, an object field) are detected.
<script setup lang="ts">
import { ref } from 'vue';
// The style filters a layer with ["global-state", "minPopulation"].
const state = ref({ minPopulation: 100000 });
</script>
<template>
<VMap :options="mapOptions" :global-state="state"></VMap>
<input v-model.number="state.minPopulation" type="range" max="5000000" />
</template>
dragRotate
- Type:
boolean | DragRotateOptions - Required:
false - Default:
undefined(MapLibre default)
Reactive drag-to-rotate behaviour. false disables it and true uses the defaults. An object picks the pivot (MapLibre 6.15+):
{ around: 'pointer' }turns and tilts around the point under the pointer, on the terrain where there is any.{ around: 'center', movement: 'circular' | 'linear' }turns around the map center.
Takes precedence over options.dragRotate.
<VMap :options="mapOptions" :drag-rotate="{ around: 'pointer' }"></VMap>
Events
@loaded
Emitted when the map has finished loading.
- Payload:
Map- The MapLibre GL Map instance
<VMap @loaded="(map) => console.log('Map ready', map)"></VMap>
Map Events
The VMap component forwards all MapLibre GL map events. You can listen to any map event using the @ directive:
<VMap
:options="mapOptions"
@click="handleClick"
@move="handleMove"
@zoom="handleZoom"
@load="handleLoad"
></VMap>
Common events include:
@load- Map loaded@click- Map clicked@dblclick- Map double-clicked@move- Map moved@movestart- Map move started@moveend- Map move ended@zoom- Map zoomed@zoomstart- Zoom started@zoomend- Zoom ended
See MapLibre GL Events for the complete list.
Slots
default
The default slot is used to nest child components like markers, popups, layers, and controls.
<VMap :options="mapOptions">
<VMarker :coordinates="[0, 0]" />
<VLayerMaplibreGeojson :source="source" :layer="layer" />
<VControlNavigation />
</VMap>
Accessing the Map Instance
Child components can access the map instance using Vue's provide/inject API:
<script setup lang="ts">
import { inject } from 'vue';
import { MapKey } from '@geoql/v-maplibre/utils/symbols';
import type { Map } from 'maplibre-gl';
import type { Ref } from 'vue';
const map = inject<Ref<Map | null>>(MapKey);
// Use the map instance
watch(map, (mapInstance) => {
if (mapInstance) {
console.log('Map instance available', mapInstance);
}
});
</script>
TypeScript
The component is fully typed with TypeScript. Import types from maplibre-gl:
import type { MapOptions, Map } from 'maplibre-gl';
Examples
Custom Style
<script setup lang="ts">
import { VMap } from '@geoql/v-maplibre';
const customStyle = {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
attribution: '© OpenStreetMap Contributors',
},
},
layers: [
{
id: 'osm',
type: 'raster',
source: 'osm',
},
],
};
const mapOptions = {
style: customStyle,
center: [0, 0],
zoom: 2,
};
</script>
<template>
<VMap :options="mapOptions" style="height: 100vh"></VMap>
</template>
With Bounds
<script setup lang="ts">
import { VMap } from '@geoql/v-maplibre';
import type { LngLatBoundsLike } from 'maplibre-gl';
const bounds: LngLatBoundsLike = [
[-74.047285, 40.679548], // Southwest
[-73.907005, 40.882214], // Northeast
];
const mapOptions = {
style: 'https://demotiles.maplibre.org/style.json',
bounds,
fitBoundsOptions: {
padding: 20,
},
};
</script>
<template>
<VMap :options="mapOptions" style="height: 500px"></VMap>
</template>