Skip to content

React Package API

The @route-optimization/react package provides React hooks and components for route visualization.

Installation

bash
npm install @route-optimization/react @route-optimization/core

Peer Dependencies:

  • react ^18.0.0
  • react-dom ^18.0.0

Components

RouteMapView

Main component for displaying routes on a map.

tsx
import { RouteMapView } from '@route-optimization/react';

<RouteMapView apiKey="YOUR_API_KEY" route={route} autoFitBounds />;

Props

PropTypeRequiredDefaultDescription
apiKeystringYes-Google Maps API key
routeRoute | nullNonullRoute to display
centerLatLngNoBangkokInitial map center
zoomnumberNo12Initial zoom level
heightstringNo'600px'Map container height
widthstringNo'100%'Map container width
autoFitBoundsbooleanNofalseAuto-fit to route bounds
onMapReady(map: google.maps.Map) => voidNo-Map ready callback
onRouteRendered(route: Route) => voidNo-Route rendered callback
onError(error: Error) => voidNo-Error callback
renderOptionsRouteRenderOptionsNo-Route styling options

Example

tsx
import { RouteMapView } from '@route-optimization/react';
import { useState } from 'react';

function App() {
  const [route, setRoute] = useState<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,
      },
    ],
  });

  return (
    <RouteMapView
      apiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY!}
      route={route}
      autoFitBounds
      height="600px"
      onMapReady={(map) => console.log('Map ready', map)}
      onError={(error) => console.error('Map error', error)}
      renderOptions={{
        color: '#4CAF50',
        polyline: {
          strokeWeight: 5,
        },
      }}
    />
  );
}

MapControls

Map control buttons for zoom and navigation.

tsx
import { MapControls } from '@route-optimization/react';

<MapControls onZoomIn={() => {}} onZoomOut={() => {}} onReset={() => {}} />;

Props

PropTypeRequiredDescription
onZoomIn() => voidNoZoom in handler
onZoomOut() => voidNoZoom out handler
onReset() => voidNoReset view handler
classNamestringNoCustom CSS class

Hooks

useRouteMap

Hook for managing a route map instance.

tsx
const { mapInstance, isLoading, error, renderRoute, clearRoute, fitBounds } = useRouteMap(config);

Parameters

typescript
interface UseRouteMapConfig {
  apiKey: string;
  mapContainer: HTMLElement | null;
  center?: LatLng;
  zoom?: number;
  onMapReady?: (map: google.maps.Map) => void;
  onError?: (error: Error) => void;
}

Returns

typescript
{
  mapInstance: google.maps.Map | null;
  isLoading: boolean;
  error: Error | null;
  renderRoute: (route: Route, options?: RouteRenderOptions) => void;
  clearRoute: () => void;
  fitBounds: () => void;
}

Example

tsx
import { useRouteMap } from '@route-optimization/react';
import { useRef, useEffect } from 'react';

function MapComponent() {
  const mapRef = useRef<HTMLDivElement>(null);

  const { mapInstance, isLoading, error, renderRoute, clearRoute } = useRouteMap({
    apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY!,
    mapContainer: mapRef.current,
    center: { lat: 13.7563, lng: 100.5018 },
    zoom: 12,
  });

  useEffect(() => {
    if (mapInstance && route) {
      renderRoute(route);
    }
  }, [mapInstance, route]);

  if (isLoading) return <div>Loading map...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <div ref={mapRef} style={{ width: '100%', height: '600px' }} />
      <button onClick={clearRoute}>Clear Route</button>
    </div>
  );
}

useMapControls

Hook for map control functionality.

tsx
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: number;
  canZoomIn: boolean;
  canZoomOut: boolean;
  zoomIn: () => void;
  zoomOut: () => void;
  setZoom: (zoom: number) => void;
  resetZoom: () => void;
}

Example

tsx
import { useMapControls } from '@route-optimization/react';

function Controls({ mapInstance }: { mapInstance: google.maps.Map | null }) {
  const { zoom, canZoomIn, canZoomOut, zoomIn, zoomOut, resetZoom } = useMapControls(mapInstance, {
    initialZoom: 12,
    minZoom: 5,
    maxZoom: 20,
    onZoomChange: (zoom) => console.log('Zoom:', zoom),
  });

  return (
    <div>
      <button onClick={zoomIn} disabled={!canZoomIn}>
        +
      </button>
      <span>Zoom: {zoom}</span>
      <button onClick={zoomOut} disabled={!canZoomOut}>
        -
      </button>
      <button onClick={resetZoom}>Reset</button>
    </div>
  );
}

Context API

MapProvider

Provides map context to child components.

tsx
import { MapProvider } from '@route-optimization/react';

<MapProvider apiKey="YOUR_API_KEY">
  <YourComponents />
</MapProvider>;

useMapContext

Access map context from child components.

tsx
import { useMapContext } from '@route-optimization/react';

function ChildComponent() {
  const { mapInstance, renderRoute } = useMapContext();

  // Use map instance and methods
}

Advanced Examples

Multiple Routes

tsx
function MultiRouteMap() {
  const [routes, setRoutes] = useState<Route[]>([]);
  const mapRef = useRef<HTMLDivElement>(null);

  const { mapInstance, renderRoute } = useRouteMap({
    apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY!,
    mapContainer: mapRef.current,
  });

  useEffect(() => {
    routes.forEach((route, index) => {
      renderRoute(route, {
        color: colors[index],
      });
    });
  }, [routes, mapInstance]);

  return <div ref={mapRef} style={{ width: '100%', height: '600px' }} />;
}

Dynamic Route Updates

tsx
function DynamicRouteMap() {
  const [route, setRoute] = useState<Route | null>(null);

  return (
    <RouteMapView
      apiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY!}
      route={route}
      autoFitBounds
      onMapReady={(map) => {
        // Map is ready
      }}
      onRouteRendered={(route) => {
        console.log('Route rendered:', route);
      }}
    />
  );
}

Custom Loading State

tsx
function CustomLoadingMap() {
  const mapRef = useRef<HTMLDivElement>(null);
  const { mapInstance, isLoading, error } = useRouteMap({
    apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY!,
    mapContainer: mapRef.current,
  });

  return (
    <div style={{ position: 'relative', width: '100%', height: '600px' }}>
      <div ref={mapRef} style={{ width: '100%', height: '100%' }} />
      {isLoading && (
        <div
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            background: 'rgba(255,255,255,0.9)',
          }}
        >
          <div>Loading map...</div>
        </div>
      )}
      {error && <div>Error: {error.message}</div>}
    </div>
  );
}

TypeScript

All components and hooks are fully typed:

tsx
import type { Route, RouteRenderOptions } from '@route-optimization/core';
import type { RouteMapViewProps } from '@route-optimization/react';

const props: RouteMapViewProps = {
  apiKey: 'YOUR_API_KEY',
  route: myRoute,
  autoFitBounds: true,
};

Next Steps

Released under the MIT License.