wakeb-map
v2.1.7
Published
A free Vue 3 multi-provider map library (Leaflet + Mapbox GL JS + extensible) with location picking, markers, geocoding, drawing, tracking, and more. No API key required for Leaflet. Works offline!
Downloads
1,170
Maintainers
Readme
wakeb-map
A free, multi-provider Vue 3 map library supporting Leaflet, Mapbox GL JS, Google Maps, and custom providers.
Default engine: Leaflet + OpenStreetMap — zero API key needed.
Includes a built-in SVG vector map engine (world maps, regions, markers, lines — no external dependencies).
Full offline support, 19 composables, 3 components, and 30+ utility functions.
Features
Components
| Component | Description |
| ------------------ | ------------------------------------------------------------------------------------------------ |
| <WakebMap> | Multi-provider map — markers, polylines, circles, polygons, drawing, fullscreen, layer switching |
| <WakebMapPicker> | Ready-made location picker — search, pin, confirm, address display |
| <WakebVectorMap> | Pure SVG vector map — world regions, data visualization, series, tooltips (zero deps) |
Composables (19)
| Category | Composables |
| ----------------- | -------------------------------------------------------------------------------------- |
| Core | useWakebMap · useDrawing · useGeofence · useMarkerCluster · useWakebTracking |
| Fleet | useFleetTracking · useRouteFollowing |
| Visualization | useChoropleth · useHeatmap · useTimeSlider |
| Routing | useRouting · useGeocoder · useElevation |
| Overlays | useImageOverlay · useWMS · useLiveData |
| UI | useMapScreenshot · useMinimap |
| Vector | useVectorMap |
Key Highlights
- 100% Free — no API key, no subscription, no usage limits (Leaflet default)
- Multi-Provider — switch between Leaflet, Mapbox GL JS, or Google Maps per-component with one prop
- Works Offline — built-in canvas tile layer, inline SVG markers, Haversine distance — all work without internet
- Vector Map Engine — pure SVG renderer with regions, markers, curved/straight lines, animated dash flow, fade-in animations, data series, tooltips, zoom/pan, touch support
- 5 Map Styles — streets, satellite, topo, dark, offline (auto-mapped across providers)
- Free Geocoding — Nominatim address search + reverse geocode
- Drawing — paths, polygons, rectangles, circles, measurements, with constraint boundaries
- Fleet Tracking — real-time vehicle/entity tracking with animated movement
- Full TypeScript — every type exported
Installation
npm install wakeb-map
vue(>=3.3) andleaflet(>=1.9.4) are peer dependencies:
npm install wakeb-map leaflet
npm install -D @types/leafletOptional: Mapbox GL JS
npm install mapbox-glThen register the provider:
import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";
import { createMapboxProvider, registerProvider } from "wakeb-map";
registerProvider(createMapboxProvider(mapboxgl));Optional: Google Maps
npm install @googlemaps/js-api-loaderThen register the provider:
import { Loader } from "@googlemaps/js-api-loader";
import { createGoogleMapsProvider, registerProvider } from "wakeb-map";
const google = await new Loader({ apiKey: "YOUR_KEY" }).load();
registerProvider(createGoogleMapsProvider(google));Quick Start
Basic Map
<template>
<WakebMap
:center="{ lat: 24.7136, lng: 46.6753 }"
:zoom="14"
:markers="markers"
height="500px"
@click="onMapClick"
@marker-click="onMarkerClick"
/>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { WakebMap } from "wakeb-map";
import "wakeb-map/style.css";
import type { WakebLatLng, WakebMarker } from "wakeb-map";
const markers = ref<WakebMarker[]>([
{
id: "1",
position: { lat: 24.7136, lng: 46.6753 },
title: "Riyadh",
snippet: "Capital of Saudi Arabia",
},
]);
function onMapClick(e: { position: WakebLatLng }) {
console.log("Clicked:", e.position.lat, e.position.lng);
}
function onMarkerClick(marker: WakebMarker) {
console.log("Marker:", marker.title);
}
</script>Location Picker
<template>
<WakebMapPicker
v-model="location"
height="500px"
confirm-label="Confirm Location"
@location-picked="onPicked"
/>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { WakebMapPicker } from "wakeb-map";
import "wakeb-map/style.css";
import type { WakebLatLng } from "wakeb-map";
const location = ref<WakebLatLng | null>(null);
function onPicked(result: { position: WakebLatLng; address: string }) {
console.log(result.position, result.address);
}
</script>Vector Map (SVG — No External Dependencies)
<template>
<div ref="mapEl" style="width: 100%; height: 400px" />
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useVectorMap } from "wakeb-map";
const mapEl = ref<HTMLElement | null>(null);
const vectorMap = useVectorMap({
map: "world",
regionStyle: {
initial: { fill: "#d1d5db", stroke: "#fff", strokeWidth: 0.5 },
hover: { fill: "#3b82f6", fillOpacity: 0.8 },
selected: { fill: "#10b981" },
},
markerStyle: {
initial: { fill: "#ef4444", stroke: "#fff", r: 6 },
hover: { fill: "#f59e0b", r: 8 },
},
lineStyle: {
stroke: "#3b82f6",
strokeWidth: 1.5,
strokeDasharray: "6 3 6",
animation: true,
curvature: 0.15,
},
zoomButtons: true,
showTooltip: true,
regionsSelectable: true,
});
onMounted(() => {
if (mapEl.value) vectorMap.init(mapEl.value);
vectorMap.addMarkers([
{ name: "Cairo", coords: [30.04, 31.24] },
{ name: "London", coords: [51.51, -0.13] },
{ name: "Tokyo", coords: [35.68, 139.69] },
]);
vectorMap.addLines([
{ from: "Cairo", to: "London" },
{ from: "London", to: "Tokyo" },
]);
});
</script>Plugin Setup (Optional)
Register globally to set default center, zoom, map type, provider, and offline options:
import { createApp } from "vue";
import { WakebMapPlugin } from "wakeb-map";
import "wakeb-map/style.css";
const app = createApp(App);
app.use(WakebMapPlugin, {
language: "ar",
defaultCenter: { lat: 24.7136, lng: 46.6753 },
defaultZoom: 14,
defaultMapType: "streets",
// provider: "mapbox", // uncomment to use Mapbox as default
// mapboxAccessToken: "pk.xxx", // required when using Mapbox
// provider: "google", // uncomment to use Google Maps as default
});
app.mount("#app");Offline Mode
Full offline support — the map, markers, shapes, GPS, and distance all work without internet.
// Option 1: Plugin config
app.use(WakebMapPlugin, {
offline: true,
offlineGridColor: "#ddd",
offlineBgColor: "#f0f0f0",
});
// Option 2: Component prop
// <WakebMap map-type="offline" />
// Option 3: Manual tile layer
import { createOfflineTileLayer } from "wakeb-map";
const offlineLayer = createOfflineTileLayer({ offlineGridColor: "#ccc" });| Feature | Offline? |
| -------------- | ---------------------------- |
| Map rendering | ✅ Canvas coordinate grid |
| Markers | ✅ Inline SVG icons (no CDN) |
| Shapes | ✅ Lines, circles, polygons |
| GPS | ✅ Browser hardware |
| Distance | ✅ Haversine formula (local) |
| Vector Map | ✅ Pure SVG (fully embedded) |
| Address search | ❌ Requires internet |
| Geocoding | ❌ Returns null gracefully |
Map Providers
Switching Providers
<!-- Default: Leaflet (no setup needed) -->
<WakebMap :center="center" :zoom="14" height="400px" />
<!-- Mapbox GL JS -->
<WakebMap
provider="mapbox"
access-token="pk.xxx"
:center="center"
:zoom="14"
height="400px"
/>
<!-- Google Maps -->
<WakebMap provider="google" :center="center" :zoom="14" height="400px" />
<!-- All three on the same page -->
<WakebMap :center="center" :zoom="14" height="400px" />
<WakebMap
provider="mapbox"
access-token="pk.xxx"
:center="center"
:zoom="14"
height="400px"
/>
<WakebMap provider="google" :center="center" :zoom="14" height="400px" />Provider Comparison
| Feature | Leaflet | Mapbox GL JS | Google Maps | | --------------- | ------------------ | -------------------- | -------------------- | | API Key | Not needed | Required (free tier) | Required (free tier) | | Tile Rendering | Raster | Vector (WebGL) | Vector | | 3D Terrain | No | Yes | Limited | | Offline Support | Yes (canvas tiles) | No | No | | Bundle Size | ~40 KB | ~200 KB | Loaded via script |
Composable Compatibility
| Composable | Leaflet | Mapbox | Google | Notes |
| ------------------- | ------- | ------ | ------ | ---------------------------------- |
| useWakebMap | ✅ | ✅ | ✅ | Provider-independent (reactive) |
| useWakebTracking | ✅ | ✅ | ✅ | Provider-independent |
| useFleetTracking | ✅ | ✅ | ✅ | Provider-independent |
| useRouteFollowing | ✅ | ✅ | ✅ | Provider-independent |
| useGeofence | ✅ | ✅ | ✅ | Provider-independent |
| useMarkerCluster | ✅ | ✅ | ✅ | Provider-independent |
| useTimeSlider | ✅ | ✅ | ✅ | Provider-independent |
| useLiveData | ✅ | ✅ | ✅ | Provider-independent |
| useVectorMap | ✅ | ✅ | ✅ | Pure SVG, no map engine dependency |
| useDrawing | ✅ | ❌ | ❌ | Leaflet L.Draw only |
| useChoropleth | ✅ | ❌ | ❌ | Leaflet GeoJSON layers |
| useHeatmap | ✅ | ❌ | ❌ | Leaflet heatmap plugin |
| useElevation | ✅ | ❌ | ❌ | Leaflet elevation control |
| useGeocoder | ✅ | ❌ | ❌ | Leaflet geocoder control |
| useImageOverlay | ✅ | ❌ | ❌ | Leaflet image overlay |
| useMapScreenshot | ✅ | ❌ | ❌ | Leaflet canvas export |
| useMinimap | ✅ | ❌ | ❌ | Leaflet minimap control |
| useRouting | ✅ | ❌ | ❌ | Leaflet routing machine |
| useWMS | ✅ | ❌ | ❌ | Leaflet WMS layer |
Map Styles
| Style | Source | Online? |
| ----------- | ------------------ | ------- |
| streets | OpenStreetMap | Yes |
| satellite | Esri World Imagery | Yes |
| topo | OpenTopoMap | Yes |
| dark | CARTO Dark | Yes |
| offline | Built-in canvas | No |
<WakebMap map-type="satellite" />
<WakebMap map-type="dark" />
<WakebMap map-type="topo" />
<WakebMap map-type="offline" />Composable Examples
useWakebMap
import { useWakebMap } from "wakeb-map";
const {
position,
address,
zoom,
markers,
loading,
setPosition,
pickMyLocation,
searchAddress,
addMarker,
distanceTo,
} = useWakebMap({ lat: 24.7136, lng: 46.6753 });useDrawing
import { useDrawing } from "wakeb-map";
const drawing = useDrawing();
drawing.bindMap(leafletMap);
drawing.startDrawing("polygon", { color: "#2196F3", showMeasurements: true });
const result = drawing.finishDrawing();useGeocoder
import { useGeocoder } from "wakeb-map";
const { search, reverse, results, loading } = useGeocoder();
await search("Kingdom Tower, Riyadh");
await reverse({ lat: 24.7136, lng: 46.6753 });useRouting
import { useRouting } from "wakeb-map";
const { calculateRoute, route, instructions } = useRouting();
await calculateRoute(
{ lat: 24.7136, lng: 46.6753 },
{ lat: 21.4225, lng: 39.8262 },
{ profile: "driving" },
);useHeatmap
import { useHeatmap } from "wakeb-map";
const { addPoints, setOptions } = useHeatmap(leafletMap);
addPoints([
{ lat: 24.71, lng: 46.67, intensity: 0.8 },
{ lat: 24.72, lng: 46.68, intensity: 0.5 },
]);useFleetTracking
import { useFleetTracking } from "wakeb-map";
const fleet = useFleetTracking(leafletMap, {
showTrails: true,
animateMovement: true,
});
fleet.updateEntity({
id: "truck-1",
type: "truck",
position: { lat: 24.7, lng: 46.6 },
});Utilities
Geocoding (Free — Nominatim)
import { reverseGeocode, geocodeAddress } from "wakeb-map";
const addr = await reverseGeocode({ lat: 24.7136, lng: 46.6753 });
const pos = await geocodeAddress("Kingdom Tower, Riyadh");Distance & Geometry
import {
calculateDistance,
calculateBearing,
midpoint,
isPointInPolygon,
isPointInCircle,
polygonArea,
pathLength,
getBoundingBox,
convexHull,
simplifyPath,
bufferPoint,
distanceMatrix,
} from "wakeb-map";
const meters = calculateDistance(
{ lat: 24.7136, lng: 46.6753 },
{ lat: 21.4225, lng: 39.8262 },
);GeoJSON Import/Export
import { exportToGeoJSON, importFromGeoJSON, downloadGeoJSON } from "wakeb-map";
const geojson = exportToGeoJSON({ markers, polylines, polygons, circles });
const data = importFromGeoJSON(geojsonObject);
downloadGeoJSON(geojson, "my-map.geojson");Props Reference
<WakebMap>
| Prop | Type | Default | Description |
| --------------------- | ----------------- | -------------------------------- | ------------------------------------------------ |
| center | WakebLatLng | { lat: 24.7136, lng: 46.6753 } | Map center |
| zoom | number | 14 | Zoom level |
| mapType | WakebMapType | 'streets' | Tile layer preset |
| provider | string | 'leaflet' | Map provider ('leaflet'/'mapbox'/'google') |
| accessToken | string | — | Mapbox access token |
| mapStyle | string | — | Mapbox style URL |
| markers | WakebMarker[] | [] | Marker array |
| polylines | WakebPolyline[] | [] | Polyline array |
| circles | WakebCircle[] | [] | Circle array |
| polygons | WakebPolygon[] | [] | Polygon array |
| routes | WakebRoute[] | [] | Route array |
| width | string | '100%' | Container width |
| height | string | '400px' | Container height |
| clickToAddMarker | boolean | false | Click to place markers |
| markerColor | string | 'red' | Default marker color |
| markerDraggable | boolean | true | Click-to-add markers draggable |
| animateMarkers | boolean | false | Smooth animated marker movement |
| showScale | boolean | false | Scale control |
| showFullscreen | boolean | false | Fullscreen button |
| showLayerSwitcher | boolean | false | Layer switcher overlay |
| showGeolocation | boolean | false | "My Location" button |
| showCoordinates | boolean | false | Cursor coordinate display |
| showDrawingToolbar | boolean | false | Drawing toolbar |
| cooperativeGestures | boolean | false | Ctrl+scroll to zoom |
| keyboardNavigation | boolean | false | Arrow key panning |
| hashRouting | boolean | false | Sync state with URL hash |
| zoomControl | boolean | true | Zoom buttons |
| options | object | {} | Extra map options (provider-specific) |
<WakebMapPicker>
| Prop | Type | Default | Description |
| ------------------- | -------------- | -------------------- | ----------------- |
| v-model | WakebLatLng | — | Selected location |
| mapType | WakebMapType | 'streets' | Map style |
| showSearch | boolean | true | Search input |
| showMyLocation | boolean | true | GPS button |
| showAddress | boolean | true | Address display |
| useCenterPin | boolean | true | Center pin mode |
| showConfirmButton | boolean | true | Confirm button |
| confirmLabel | string | 'Confirm Location' | Button text |
Events
<WakebMap>
| Event | Payload | Description |
| ----------------- | ------------------------------------------------------- | --------------------------- |
| click | { position, originalEvent } | Map click |
| markerClick | WakebMarker | Marker click |
| markerDragEnd | (marker, newPosition) | Marker drag end |
| markerDragStart | WakebMarker | Marker drag start |
| markerAdded | WakebMarker | Marker added (click-to-add) |
| markerRemoved | markerId | Marker removed |
| cameraChange | WakebCameraPosition | Viewport change |
| mapReady | native map instance | Map initialized |
| providerReady | WakebMapProviderInstance | Provider instance ready |
| drawComplete | WakebDrawnPath \| WakebDrawnShape \| WakebMeasurement | Drawing finished |
| drawUpdate | same | Drawing updated |
| geolocation | WakebLatLng | User location acquired |
| update:center | WakebLatLng | Center changed |
| update:zoom | number | Zoom changed |
<WakebMapPicker>
| Event | Payload | Description |
| ------------------- | ----------------------- | ------------------ |
| update:modelValue | WakebLatLng | Location updated |
| locationPicked | { position, address } | Location confirmed |
Documentation
Full interactive docs with live demos:
visit the hosted docs at wakeb-map.surge.sh
License
MIT © Kerolos Zakaria
