Search code examples
reactjsleafletreact-leafletleaflet-routing-machine

how to add leaflet routing machine control to another div instead of map: react-leaflet


I want to display routing machine control div on dashboard (collapse side bar like google maps) instead of map div, because it is covering the map on mobile version. is there any easier way to do that? I have tried this 2 ways : appending control div to another div , appending control div with onAdd(map)

I have 3 components MapComponent, RoutingMachine and Dashboard.

RoutingMachine.jsx

import React from "react";
import L, { control, Map, map, routing } from "leaflet";
import { createControlComponent } from "@react-leaflet/core";
import "leaflet-routing-machine";
import 'lrm-graphhopper'
import "leaflet-routing-machine/dist/leaflet-routing-machine.css";
import { useEffect } from "react";
import { useMap } from "react-leaflet";


const createRoutineMachineLayer = ({ userLat, userLong, bikeLat, bikeLong }) => {
  
  const instance = L.Routing.control({
    waypoints: [
      L.latLng(userLat, userLong),
      L.latLng(bikeLat, bikeLong)
    ],
    lineOptions: {
      styles: [{ color: "#6FA1EC", weight: 4 }]
    },
    createMarker: function() {
      return null
    },
    router: new L.Routing.GraphHopper('deebe34a-a717-4450-aa2a-f6de3ec9b443', {
      urlParameters: {
          vehicle: 'foot'
      }}),
    show: true,
    addWaypoints: false,
    routeWhileDragging: true,
    draggableWaypoints: true,
    fitSelectedRoutes: true,
    showAlternatives: false
  })

  return instance;
};

const RoutingMachine = createControlComponent(createRoutineMachineLayer);

export default RoutingMachine;

Solution

  • You can achieve that behavior using two refs. One will be the div to attach the control and the other other one the ref of the routing machine instance.

    const Map = () => {
      const [map, setMap] = useState(null);
      const routingMachineRef = useRef();
      const pluginRef = useRef();
    
      useEffect(() => {
        if (!map) return;
        const controlContainer = routingMachineRef.current.onAdd(map);
        pluginRef.current.appendChild(controlContainer);
      }, [map]);
      ...
    
      <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(2, minmax(0, 1fr))"
      }}
    >
      <MapContainer... 
         <RoutineMachine ref={routingMachineRef} />
      </MapContainer>
      <div style={{ border: "1px solid black" }} ref={pluginRef} />
    </div>
    );
    };
    

    In this demo you can find the control attached in a div vertically. You can modify it to place it horizontally under the map if you want or anywhere else that fit your needs.

    Demo