1

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 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Now the elements get deleted and recreated so there are no leftover trash elements. Your solution is a lot better compared to what I have set up now. But the most performant way to solve this would be to show/hide. I'll investigat your solution
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.