Leaflet mapping - remove an overlay div?


#1

Hi,
so i’m just getting to grips with leaflet and have a full working map with data being pulled from a mysql db and clustering and custom icons etc so i am reasonably far in.

Now i want an info panel that is originally loaded when the map loads to tell users about some of the features. But i want them to then close/minimise that as it will then just obscure the map.

I’ve found this page https://leafletjs.com/examples/extending/extending-3-controls.html but it doesnt’ tell me how to remove the panel. The example they have is

L.Control.Watermark = L.Control.extend({
    onAdd: function(map) {
        var img = L.DomUtil.create('img');

        img.src = '../../docs/images/logo.png';
        img.style.width = '200px';

        return img;
    },

    onRemove: function(map) {
        // Nothing to do here
    }
});

L.control.watermark = function(opts) {
    return new L.Control.Watermark(opts);
}

L.control.watermark({ position: 'bottomleft' }).addTo(map);

It talks about the onRemove function but i am unsure how to use it. I assume i need to add a button into the info panel which an event handler listens to and triggers the onRemove. It might even need a cookie to remember the close so when filters are applied it doesn’t pop back up. But I’m not very versed in JS and don’t know where to start or if this thinking is correct.

Any help or directions to information on this would be appreciated.


#2

Well, lets do some thinking.

Examples aren’t there to tell you how to do things, they’re there to walk you through the specific thing that they’ve chosen for an example.
Rather than looking at the examples and trying to extrapolate information not present, we need to look at, as you identified yourself:

translation to programmer speak: “I need the documentation.”

Fortunately, on the page you linked, there’s a link at the top which reads “Docs”. That’s your starting location.

Now, the example you’re using invokes a fair few number of commands, but all of the Leaflet ones stem off of L.

Stepping Backwards

To backtrace what the script is doing, first you find the thing that’s not a function, but that’s doing functions. In this case, that would be the last line.
L.control.watermark().addTo()
(Note: I don’t particularly care about the parameters, just the function names.)
addTo() seems fairly straightforward to me, it wants to slap whatever the object it’s referring to onto the map.
watermark() might be interesting, so lets find out what that is.
There’s nothing defining just watermark, so we have to be a little intuitive. Start at the beginning of the line, to figure out what object is being handed to .watermark.
L we know is Leaflet. Nothing to see there.
L.control… Now, here the example does something that I find not to be good code practice: Javascript is case-sensitive. I can look into my Leaflet documentation and see that Leaflet has a default class inside it called Control. I may be confused and think that that is what this refers to. I would be wrong. control != Control. So, I have to assume (and may be able to see elsewhere in the code) that they have declared L.control in some form. (Turns out in their tutorials they dont, and this is sloppy.)
Failing to find a definition for L.control, I have a couple of tools at my disposal; the javascript console, in particular, may be helpful here. typeof(L.control) should (untested) identify L.control as a bog standard Javascript Object.
So if L.control is an object, that means .watermark is a property of that object. Well, given that there’s no definition for L.control in the docs, We need to find something that defines L.control.watermark. Ah, there it is elsewhere in the code. L.control.watermark is a function, that takes one parameter (opts), and returns an object (indicated by the word new) of type L.Control.Watermark.

Now remember when I said that Javascript was case sensitive? So now we’ve gotta start allll over again, but using the capital versions. We know what L is, but this time L.Control IS defined in our docs - it’s one of the standard classes. So we open up the Control page in our docs, and search for Watermark and… it’s not there. Hrm. Okay, then the script must be defining L.Control.Watermark for us. Let’s search the code… ah here we go, L.Control.Watermark is equal to… L.Control.extend(…)

Okay… i dont know what L.Control.extend is. I can search through the docs for extend, and find a definition in a few different places, but eventually i’ll find that .extend() is a sort of global function for Leaflet classes, that allows extension. If you don’t understand class inheritance and extension, Here’s some technical detail, but effectively understand that Leaflet defines its own way of things to inherit from other classes, and that L.Control.extend will return (effectively) a class definition that is a child class of Control.

Rolling upwards again

So; now I know that L.control.watermark will eventually be an Object, of a class “Watermark”,which is a subclass of type “Control” (Can you see why I said this is a bad coding practice? reusing ‘control’ and ‘watermark’ in two different contexts gets confusing.). where is .addTo defined? I see an onAdd inside the extend call, but not an addTo. We must intuit then that it inherited that method from its parent type, L.Control.

Back to the docs to verify our intuition, and in the definition for Control, yes, we can see the addTo method, which “Adds the control to the given map.”
Not coincidentally, the next line should catch our attention also.
remove() “Removes the control from the map it is currently active on.”

Aha. There’s our command to remove the item from the map. But where do we invoke it?

Instinct is going to pull you towards onRemove. But that will fire when the thing is removed, not… trigger the removal. It’s a reaction, not an action.

How you choose to wire up the remove depends on you, and how you implemented the watermark to begin with. But at some point you will bind an event on some object (even to the image itself possibly) to a click that will call L.control.watermark.remove();

If you want to deepdive yourself and target that img tag, take a look at the Leaflet docs for the function that creates the image, what its returntype is, and then take a look at the DomEvent section of the docs. It should become clearer.


#3

wow thanks for that reply. That’s going to take some thinking about. Will have a go and see how far i get then no doubt will be back. Possibly for more or hopefully with a solution…

thanks