Leaflet Routing Machine hide route without using .remove()

5k Views Asked by At

enter image description here

How do should I hide the Leaflet Routing Machine route and markers on mouseout event?

Currently, I have regular Leaflet marker, that has mouseover/mouseout events. When mouseover event is fired and route belonging to that marker is created using L.Routing.control

    route = L.Routing.control({
      show: false,
      addWaypoints: false,
      draggableWaypoints: false,
      fitSelectedRoutes: false,
      waypoints: [
        L.latLng(locations.aLat, locations.aLng), // Hardcoded coordinates
        L.latLng(locations.bLat, locations.bLng), // Hardcoded coordinates
      ],
    });
    route.addTo(map);

When mouseout event is triggered I call route.remove() which deletes the route completely.

The problem with this approach:

  • It takes a little bit less than half a second to retrieve route from OSRM server
  • Every single mouseover event sends a request to an OSRM server

I have tried to set route opacity to 0 and marker icon size to 0 on mouseout event, however, you cannot dynamically change styles in Leaflet Routing Machine.

Another approach I took was to give css class names to routes and try to set display: none but assigning classes to many different routes is a really messy way to solve this.

The demo is quite neat if you want to play around.(Updated works as supposed to) Grab it here

2

There are 2 best solutions below

0
On BEST ANSWER

The solution is to create the route once and save it somewhere for later use. In my case, it is saved on marker.options

marker = L.marker(pointA, {
options: {
  route: createRoute(pointA, pointB), // Function that return route object(L.Routing.control)
 },
})

After you have the route created you can:

  • Check if it is on the map:
    if (marker.options.options.route._map) { Do something }
  • Add it to the map:
    marker.options.options.route.addTo(map);
  • Remove it from the map:
    marker.options.options.route.remove();

You can find a working demo here

1
On

In situations like this where you may repeatedly call an expensive or IO related function with the same arguments, it's best to wrap that function in a memoizing callable.

Such a function will compute the value once, then store it and return the stored value if it is requested again.

For example:

function very_expensive(argument) {
    //.....
    return stuff
}

let cache = {}

function from_cache(argument) {
    if (!(argument in cache)) {
        cache[argument] = very_expensive(argument);
    }

    return cache[argument]
}

The problem with hiding but not removing is that the layer is still in the DOM, and if you have a lot of those invisible elements (which may happen quite quickly if your users scroll over a lot of markers), this can degrade performance. It's also a much messier solution.

For the same reason, use a lru cache as this only stores the most recent ones, preventing the cache from growing without bounds. There are several implementations on NPM if you aren't rolling your own.