Best way to temporary remove DOM events on a layer

831 views
Skip to first unread message

Jean-Félix Girard

unread,
Aug 7, 2012, 3:02:47 PM8/7/12
to leafl...@googlegroups.com
Hi,

I'm doing some tests with the Draw tools from https://github.com/jacobtoye/Leaflet.draw.   When there are interactive layer on the map (clickable marker, Path, ...),  they capture the click event (and stop the propagation) before the Draw Handler get the DOM event.  

The result is I cannot create a vertex (for the shape being created) on top of a clickable layer.

What I want is to make all layers not clickable when I activate a draw tool.   

I can remove all the clickable layers and add them back with options.clickable=false but its a lot of overhead and it makes the markers flicker.  

I just want to remove the DOM events while the draw tool is active and then put them back after. So, I added 2 functions to add and remove the dom events when needed:

L.Path.include({

    _initEvents: function() {
        this.addEvents();
    },

    addEvents: function() {
        if (this.options.clickable) {
            if (L.Browser.svg || !L.Browser.vml) {
                this._path.setAttribute('class', 'leaflet-clickable');
            }

            L.DomEvent.on(this._container, 'click', this._onMouseClick, this);

            var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'mousemove', 'contextmenu'];
            for (var i = 0; i < events.length; i++) {
                L.DomEvent.on(this._container, events[i], this._fireMouseEvent, this);
            }
        }
    },

    removeEvents: function() {
        if (L.Browser.svg || !L.Browser.vml) {
            this._path.setAttribute('class', '');
        }
        L.DomEvent.off(this._container, 'click', this._onMouseClick, this);

        var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'mousemove', 'contextmenu'];
        for (var i = 0; i < events.length; i++) {
            L.DomEvent.off(this._container, events[i], this._fireMouseEvent, this);
        }
    }
});

L.Marker.include({

    _initInteraction: function() {
        this.addEvents();
if (L.Handler.MarkerDrag) {
            this.dragging = new L.Handler.MarkerDrag(this);

            if (this.options.draggable) {
                this.dragging.enable();
            }
        }
    },

    addEvents: function() {
        if (!this.options.clickable) {
            return;
        }

        var icon = this._icon,
        events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];

        L.DomUtil.addClass(icon, 'leaflet-clickable');
        L.DomEvent.on(icon, 'click', this._onMouseClick, this);

        for (var i = 0; i < events.length; i++) {
            L.DomEvent.on(icon, events[i], this._fireMouseEvent, this);
        }    
    },

removeEvents: function() {
        var icon = this._icon,
        events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];
        L.DomUtil.removeClass(icon, 'leaflet-clickable');
        L.DomEvent.off(icon, 'click', this._onMouseClick, this);

        for (var i = 0; i < events.length; i++) {
            L.DomEvent.off(icon, events[i], this._fireMouseEvent, this);
        }
    }
});



I works but I don't feel right about it. I had to copy / paste a lot of code :(

Is there a better way to do it ?

Thanks.

Jeff

Jacob Toye

unread,
Oct 4, 2012, 10:13:10 PM10/4/12
to leafl...@googlegroups.com
Hi Jeff,

I maintain the Leaflet.draw plugin :) I just came across this post today, sorry haven't looked much around the Leaflet Google Group.

I've just tackled the issue you are talking about here. See https://github.com/jacobtoye/Leaflet.draw/issues/23

What I ended up doing is placing a transparent marker under the mouse when in 'drawing' mode. This marker catches all the mouse click events and is set to be above any other map layers. To be honest I went over a few different solutions and (surprisingly) this was the least hacky solution I could come up with ;)

Cheers,
Jacob
Reply all
Reply to author
Forward
0 new messages