2

LeafletJS. I am trying to have two overlay layers be mutually exclusive. Full example here on jsfiddle

I guess it comes down to this bit of code:

        map.on('overlayadd', function(event)
        {
            console.log( "Clicked on " + event.name )
            if ( event.name == "layer1" && map.hasLayer(layer2) ) {
                console.log("remove layer2")
                map.removeLayer(layer2)
            }
            if ( event.name == "layer2" && map.hasLayer(layer1) ) {
                console.log("remove layer1")
                map.removeLayer(layer1)
            }
            ccontrol._update();
        });

It I select just layer2 and then select layer1 it works fine (layer1 becomes selected and shown on map and layer2 toggles to off). The Console shows the sequence of events to be:

  • Clicked on layer2
  • Clicked on layer1
  • remove layer2

But if I select layer1 first, and then try to select layer 2 nothing appears to happen. The console shows the sequence of events to be:

  • Clicked on layer1 <-- I manually clicked this
  • Clicked on layer2 <-- I manually clicked this
  • remove layer1
  • Clicked on layer1 <-- This happened automatically ???
  • remove layer2

Can anyone shed some light on this?

1 Answer 1

1

Problem comes from your use of internal layer control method ._update(). It's never wise to us internals, since you do not know exactly how/when they should be used and what the consequences are.

You are using it to refresh layer switcher control, since it does not want to refresh itself if layers are added/removed within overlayadd event processing function. Solution for this is to add/remove layer async with the help of setTimeout function.

Your code could then look something like this:

function removeWithTimeout(layer) {
  setTimeout(function() {
    map.removeLayer(layer);
  }, 10);
}

map.on('overlayadd', function(event)
{
  console.log( "Clicked on " + event.name )
  if ( event.name == "layer1" && map.hasLayer(layer2) ) {
    console.log("remove layer2");
    removeWithTimeout(layer2);
  }
  if ( event.name == "layer2" && map.hasLayer(layer1) ) {
    console.log("remove layer1");
    removeWithTimeout(layer1);
  }
});
2
  • Thank you. This works (which you knew), but it does seem quite hacky. Can you say anything about why it works? Is it a JavaScript or Leaflet feature?
    – Buzz
    Commented Dec 16, 2020 at 11:16
  • I'm no JS expert, but I would say that this behavior is consequence of executing control method that fires events within event processing function of the same control. Using setTimeout to execute this function enables it's execution after original event processing is finished.
    – TomazicM
    Commented Dec 16, 2020 at 14:41

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.