Vue Package API
The @route-optimization/vue package provides Vue 3 composables and components for route visualization.
Installation
bash
npm install @route-optimization/vue @route-optimization/corePeer Dependencies:
vue^3.3.0
Components
RouteMapView
Main component for displaying routes on a map.
vue
<template>
<RouteMapView :api-key="apiKey" :route="route" auto-fit-bounds />
</template>Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey | string | Yes | - | Google Maps API key |
route | Route | null | No | null | Route to display |
center | LatLng | No | Bangkok | Initial map center |
zoom | number | No | 12 | Initial zoom level |
height | string | No | '600px' | Map container height |
width | string | No | '100%' | Map container width |
autoFitBounds | boolean | No | false | Auto-fit to route bounds |
Events
| Event | Payload | Description |
|---|---|---|
map-ready | google.maps.Map | Emitted when map is initialized |
route-rendered | Route | Emitted when route is rendered |
error | Error | Emitted on error |
Slots
| Slot | Props | Description |
|---|---|---|
loading | - | Custom loading state |
error | { error: Error } | Custom error display |
Example
vue
<script setup lang="ts">
import { RouteMapView } from '@route-optimization/vue';
import type { Route } from '@route-optimization/core';
import { ref } from 'vue';
const apiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;
const route = ref<Route>({
id: 'route-1',
vehicleId: 'vehicle-1',
stops: [
{
id: 'start',
location: { lat: 13.7563, lng: 100.5018 },
type: 'START',
sequence: 0,
},
{
id: 'delivery',
location: { lat: 13.7467, lng: 100.5342 },
type: 'DELIVERY',
label: 'Customer #1',
sequence: 1,
},
],
});
const handleMapReady = (map: google.maps.Map) => {
console.log('Map ready', map);
};
const handleError = (error: Error) => {
console.error('Map error', error);
};
</script>
<template>
<RouteMapView
:api-key="apiKey"
:route="route"
auto-fit-bounds
height="600px"
@map-ready="handleMapReady"
@error="handleError"
>
<template #loading>
<div class="loading">Loading map...</div>
</template>
<template #error="{ error }">
<div class="error">Error: {{ error.message }}</div>
</template>
</RouteMapView>
</template>MapControls
Map control buttons for zoom and navigation.
vue
<template>
<MapControls
:map-instance="mapInstance"
:show-zoom-level="true"
@zoom-change="handleZoomChange"
/>
</template>Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
mapInstance | google.maps.Map | null | Yes | - | Map instance |
initialZoom | number | No | 12 | Initial zoom level |
minZoom | number | No | 5 | Minimum zoom level |
maxZoom | number | No | 20 | Maximum zoom level |
showZoomLevel | boolean | No | true | Show zoom level display |
showResetButton | boolean | No | true | Show reset button |
Events
| Event | Payload | Description |
|---|---|---|
zoom-change | number | Zoom level changed |
zoom-in | - | Zoom in clicked |
zoom-out | - | Zoom out clicked |
reset | - | Reset clicked |
Slots
| Slot | Props | Description |
|---|---|---|
before-controls | - | Content before controls |
after-controls | - | Content after controls |
zoom-in-icon | - | Custom zoom in icon |
zoom-out-icon | - | Custom zoom out icon |
reset-icon | - | Custom reset icon |
Composables
useRouteMap
Composable for managing a route map instance.
typescript
const { mapInstance, isLoading, error, renderRoute, clearRoute, fitBounds } = useRouteMap(options);Parameters
typescript
interface UseRouteMapOptions {
apiKey: string;
container: Ref<HTMLElement | null>;
center?: LatLng;
zoom?: number;
onMapReady?: (map: google.maps.Map) => void;
onError?: (error: Error) => void;
}Returns
typescript
{
mapInstance: Ref<google.maps.Map | null>;
isLoading: Ref<boolean>;
error: Ref<Error | null>;
renderRoute: (route: Route, options?: RouteRenderOptions) => void;
clearRoute: () => void;
fitBounds: () => void;
}Example
vue
<script setup lang="ts">
import { useRouteMap } from '@route-optimization/vue';
import { ref, watch } from 'vue';
const mapContainer = ref<HTMLElement | null>(null);
const route = ref<Route | null>(null);
const { mapInstance, isLoading, error, renderRoute, clearRoute, fitBounds } = useRouteMap({
apiKey: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
container: mapContainer,
center: { lat: 13.7563, lng: 100.5018 },
zoom: 12,
onMapReady: (map) => {
console.log('Map ready', map);
},
});
watch(route, (newRoute) => {
if (newRoute && mapInstance.value) {
renderRoute(newRoute);
}
});
const handleClearRoute = () => {
clearRoute();
route.value = null;
};
</script>
<template>
<div>
<div v-if="isLoading">Loading map...</div>
<div v-if="error">Error: {{ error.message }}</div>
<div ref="mapContainer" style="width: 100%; height: 600px" />
<button @click="handleClearRoute">Clear Route</button>
</div>
</template>useMapControls
Composable for map control functionality.
typescript
const { zoom, canZoomIn, canZoomOut, zoomIn, zoomOut, setZoom, resetZoom } = useMapControls(
mapInstance,
options
);Parameters
typescript
interface UseMapControlsOptions {
initialZoom?: number;
minZoom?: number;
maxZoom?: number;
onZoomChange?: (zoom: number) => void;
}Returns
typescript
{
zoom: Ref<number>;
canZoomIn: ComputedRef<boolean>;
canZoomOut: ComputedRef<boolean>;
zoomIn: () => void;
zoomOut: () => void;
setZoom: (zoom: number) => void;
resetZoom: () => void;
}Example
vue
<script setup lang="ts">
import { useMapControls } from '@route-optimization/vue';
import { ref } from 'vue';
const mapInstance = ref<google.maps.Map | null>(null);
const { zoom, canZoomIn, canZoomOut, zoomIn, zoomOut, resetZoom } = useMapControls(mapInstance, {
initialZoom: 12,
minZoom: 5,
maxZoom: 20,
onZoomChange: (zoom) => {
console.log('Zoom changed to:', zoom);
},
});
</script>
<template>
<div class="map-controls">
<button @click="zoomIn" :disabled="!canZoomIn">+</button>
<span>Zoom: {{ zoom }}</span>
<button @click="zoomOut" :disabled="!canZoomOut">-</button>
<button @click="resetZoom">Reset</button>
</div>
</template>Advanced Examples
Reactive Route Updates
vue
<script setup lang="ts">
import { RouteMapView } from '@route-optimization/vue';
import { ref, watch } from 'vue';
const route = ref<Route>({
id: 'route-1',
vehicleId: 'vehicle-1',
stops: [],
});
// Add stops dynamically
const addStop = (location: LatLng) => {
route.value = {
...route.value,
stops: [
...route.value.stops,
{
id: `stop-${route.value.stops.length}`,
location,
type: 'DELIVERY',
sequence: route.value.stops.length,
},
],
};
};
// Component automatically re-renders when route changes
</script>
<template>
<RouteMapView :api-key="apiKey" :route="route" auto-fit-bounds />
</template>Custom Styling with Composable
vue
<script setup lang="ts">
import { useRouteMap } from '@route-optimization/vue';
import { ref, watchEffect } from 'vue';
const mapContainer = ref<HTMLElement | null>(null);
const route = ref<Route | null>(null);
const color = ref('#4CAF50');
const { mapInstance, renderRoute } = useRouteMap({
apiKey: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
container: mapContainer,
});
watchEffect(() => {
if (route.value && mapInstance.value) {
renderRoute(route.value, {
color: color.value,
polyline: {
strokeWeight: 6,
strokeOpacity: 0.9,
},
});
}
});
</script>
<template>
<div>
<input v-model="color" type="color" />
<div ref="mapContainer" style="width: 100%; height: 600px" />
</div>
</template>Multiple Routes
vue
<script setup lang="ts">
import { useRouteMap } from '@route-optimization/vue';
import { ref, watch } from 'vue';
const mapContainer = ref<HTMLElement | null>(null);
const routes = ref<Route[]>([]);
const { mapInstance, renderRoute, clearRoute } = useRouteMap({
apiKey: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
container: mapContainer,
});
const colors = ['#FF5722', '#2196F3', '#4CAF50'];
watch([routes, mapInstance], ([newRoutes, map]) => {
if (map && newRoutes.length > 0) {
clearRoute();
newRoutes.forEach((route, index) => {
renderRoute(route, {
color: colors[index % colors.length],
});
});
}
});
</script>
<template>
<div ref="mapContainer" style="width: 100%; height: 600px" />
</template>TypeScript Support
All composables and components are fully typed:
typescript
import type { Route, RouteRenderOptions } from '@route-optimization/core';
import type { UseRouteMapOptions } from '@route-optimization/vue';
const options: UseRouteMapOptions = {
apiKey: 'YOUR_API_KEY',
container: mapContainer,
center: { lat: 13.7563, lng: 100.5018 },
zoom: 12,
};CSS Customization
Components include scoped styles that can be customized:
vue
<style scoped>
.route-map-view {
/* Custom styles */
}
.map-controls {
/* Custom control styles */
}
</style>