I am using google maps + javascript + php in my application.
I want to know two things:
In google maps,
does moveend event ALWAYS gets fired
AFTER zoomend/dragend (whichever of
two) event occurs.
When I click zoom icon on google map
or scroll the mouse wheel to zoom,
the zoomend event gets fired more
than once. If I zoom in one step
using + icon on map, the zoomend
event gets fired twice or sometimes
more. any possible loophole.
And so want to know how to stop further event propogation in javascript. (remember I need not use clearListeners as it will forever ignore event handler which is undesirable).
Thank you.
I set up listeners for 'moveend', 'zoomend', and 'dragend' to try it out.
GEvent.addListener(map, "moveend", function() { console.log('moveend'); });
GEvent.addListener(map, "zoomend", function() { console.log('zoomend'); });
GEvent.addListener(map, "dragend", function() { console.log('dragend'); });
It appears that 'moveend' always fires after 'zoomend' or 'dragend'.
However, no events ever fired more than once at a time. Maybe you accidentally set up two simultaneous listeners. You shouldn't need to use stopPropagation or cancelBubble.
you could try just reuturning false or null from the event.
If that doesn't work trying using "event.cancelBubble = true" or "event.stopPropagation"
Related
I have a simple question that has me stumped:
In a Leaflet application, I have an event listener for clicking elements on the map:
marker.on('click', function () {
doStuff();
$('element').doStuff();
setView(this.getLatLng());
});
However, the setView method also triggers a 'map moved' event, which I do not want to fire. Using either plain JavaScript or jQuery, can I prevent any other event from firing while inside the click event function?
Edit: now with a Fiddle! To use it, just click anywhere on the map. As you can see, e.stopPropagation() does not work when placed inside the click event listener.
http://jsfiddle.net/gc6e4jbg/
I don't believe you can prevent moveend being fired. (NB: these aren't jQuery events - Leaflet has its own internal event system.) This is the source for setView:
setView: function (center, zoom) {
zoom = zoom === undefined ? this.getZoom() : zoom;
this._resetView(L.latLng(center), this._limitZoom(zoom));
return this;
}
_resetView always fires moveend at the end:
_resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) {
var zoomChanged = (this._zoom !== zoom);
if (!afterZoomAnim) {
this.fire('movestart');
if (zoomChanged) {
this.fire('zoomstart');
}
}
...
this.fire('moveend', {hard: !preserveMapOffset});
}
You could investigate customizing these functions to allow for suppression of the event.
Update:
Alternatively, you could change your moveend event handler. Have it track a flag, which you set when you don't want the normal operations to happen.
For example, you'll have set up your handler similar to:
map.on('moveend', myHandler);
Have myHandler do something like:
function myHandler(e) {
if (stopFlag) {
return;
}
else {
// Normal operation
...
}
}
Then just enable and disable stopFlag to control the flow. The advantage of this is that you don't have to publish a custom version of Leaflet with your application.
To be straight to the point: that will never work. By using stopPropagation/preventDefault you stop the click event from bubbling up through the dom. Nothing else. Once you execute L.Map's setView method it will always fire the moveend event, it's got nothing to do with the click event. It will also the fire movestart and move events and even the resetview event if you also set the zoomlevel in setView. That's just the way Leaflet works. You could always extend L.Map to write you own logic but i'm guessing you're better of finding another solution to your problem.
Use event.stopPropagation(), see the docs
marker.on('click', function (e) {
e.stopPropagation();
}
Here is my a bit more hackish solution.
At the beginning
Set moveend to true as a default value.
var moveend = true;
Inside a click event
Set moveend to false.
moveend = false;
map.setView(new L.LatLng(lat, lng));
moveend event
Do something if moveend is true. No matter what, set moveend to true for next run.
map.on('moveend', (e) => {
if (moveend) {
// Do something if moveend is enabled
}
moveend = true;
});
In one of our projects we're using Leaflet along with Leaflet.markercluster plugin. Looking through the Leaflet's sources I found that it appends _collapse() function to the map's click event, so whenever I click on the map it contracts previously expanded cluster.
Now, I want to disable this behavior. If the cluster is expanded, then I just want to deselect all of its markers on click event (and don't contract the cluster itself). Here is the piece of my code:
map.on('click', function(e) {
scope.deselectAllMarkers();
});
I tried to add the following lines in the end of this one-line callback in order to stop propagation of click event:
scope.L.DomEvent.stopPropagation(e);
scope.L.DomEvent.preventDefault(e);
scope.L.DomEvent.stop(e);
scope.L.DomEvent.stopPropagation(e.originalEvent);
scope.L.DomEvent.preventDefault(e.originalEvent);
scope.L.DomEvent.stop(e.originalEvent);
And none of them works. Default listener which is hidden inside of the Leaflet sources keeps its invocation whenever I click on the map. Am I missing something?
I know that this answer is quite late, but if someone is interested in a solution, here is how i have solved it.
This snippet here below is an example of binding a function to the click event.
map.on('click', doSomething);
Actually, after checking leaflet's API and some geekish debugging, it seems that the event returns an object, not the event itself. The event itself is wrapped into a field within the returned object.
var doSomething = function(map) {
// stop propagation
map.originalEvent.preventDefault();
};
When using the above snippet, the event bubbling has stopped, something which i wanted, and probably what you wanted.
This one worked for me...
var div = L.DomUtil.get('div_id');
if (!L.Browser.touch) {
L.DomEvent.disableClickPropagation(div);
L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
} else {
L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
}
Thanks to https://gis.stackexchange.com/questions/104507/disable-panning-dragging-on-leaflet-map-for-div-within-map
I know that this answer is event more quite late, but as in jquery you can use .off
map.on('click', doSomething);
map.off('click');
It works fine for any leaflet events.
I use it for 'zoomend' event to be triggered one time only.
map.on('moveend', function(e){
console.log("any code");
map.off('moveend');
});
You can't override the event propagation from an event handler. You need to use the builtin Leaflet helper after the page has loaded, like this:
$('.element').each (i,el)->
L.DomEvent.disableClickPropagation(el);
In the end I've solved the issue by manual removal of default click handler which was invoking the _collapse() method, as far as I remember. Dirty, but it did the trick.
You have use like this event.stopPropagation()
map.on('click', function(e) { //don't forget to pass this 'e' event parameter
e.preventDefault();
scope.deselectAllMarkers();
e.stopPropagation();
return false;
});
Try anyone of this
1.event.stopPropagation()
2.event.preventDefault()
3.return false
I am implementing an app using Google Maps API 3. I would like to know what is the best implementation in dealing with this problem. I want to execute an action once ANY event in Google Map has been fired. Currently, what I am doing is that I call the function every time a specific event is called. I find this redundant and I have to make a listener for all of the events. So, is there a way to generalize this where I can do the following:
google.maps.addListener(everything_on_the_map_canvas, 'ANY_EVENT', function(event) {
foo();
})
function foo(){
//do something here
}
Thank you.
If the user decides to continue with map operations, they will have to move the mouse over the map to do anything. So you could simply trap a mousemove.
google.maps.event.addListener(map, 'mousemove', function(event) {foo();})
If the user can manipulate the map without moving the mouse over the map, then you will need to listen to other events.
bounds_changed will cover most eventualities with zoom and pan, heading and the like
maptype_id_changed
But that's only three instead of all of them. If the bounds don't change when the tilt does (and you can change tilt from outside the map) you may need to listen for tilt_changed as well.
I have a problem using balloons in google earth.
I have some markers on the map, upon clicking on a marker, a balloon popup is shown containing some data, now when I click on the close button of that balloon, the click event of the map is also triggered which is really annoying as I have a handler attached with the map click event.
I tried everything including using event.stopPropagation() in the 'beforeclose' event of the htmlDivBalloon but still nothing works.
Anyone has an idea about that ?
Best Regards
John Tadros
The chances are you are not handling the default event or you are not screening which objects the event acts in the handler "attached with the map click event". You haven't shown any code, so it is hard to say exactly how to fix it - but a generic way to handle this is as follows.
// listen for mousedown on the window
google.earth.addEventListener(ge.getWindow(), 'mousedown', function(e) {
var type = e.getTarget().getType();
if (type == 'KmlPlacemark') {
// prevent the default event for placemarks, stop Propagation
e.preventDefault();
e.stopPropagation();
} else if(type == 'GEGlobe') {
// do something with the globe...
}
// etc...
});
Here's the situation:
On my Google Map, I'm trying to open an html info window whenever the user moves its mouse over a GMarker.
This window should be closed when the pointer is out of the marker.
GEvent.addListener(my_marker, "mouseover", function() {
MaCarte.openInfoWindowHtml(new GLatLng(my_marker.getLatLng().lat()+0.002, my_marker.getLatLng().lng()+0.001),"some text");
});
GEvent.addListener(my_marker, "mouseout", function() {
if((MaCarte.getInfoWindow().getPoint().lat() == my_marker.getLatLng().lat()+0.002)
&& (MaCarte.getInfoWindow().getPoint().lng() == my_marker.getLatLng().lng()+0.001))
MaCarte.closeInfoWindow();
});
What happens is that the onmouseout event is fired too soon, so the info window opens and closes right after it.
My guess is that the mouse no longer is over the marker but over the info window causing the onmouseout to be fired.
How can I do to let the info window open until my pointer is actually out of the marker?
I would use a timer and variable that dictates whether it's ok to close the window. Basically, have a timer start in the mouseover event and that timer changes a variable. The mouseout event then only closes the window if it's ok to close
like
GEvent.addListener(my_marker, "mouseover", function() {
timer.start()
MaCarte.openInfoWindowHtml(new GLatLng(my_marker.getLatLng().lat()+0.002, my_marker.getLatLng().lng()+0.001),"some text");
});
GEvent.addListener(my_marker, "mouseout", function() {
if (okToClose){
if((MaCarte.getInfoWindow().getPoint().lat() == my_marker.getLatLng().lat()+0.002)
&& (MaCarte.getInfoWindow().getPoint().lng() == my_marker.getLatLng().lng()+0.001))
MaCarte.closeInfoWindow();
}
});
This doesn't directly answer your question, but it will work as a workaround.
Hope it helps!
Chris
One thing that can happen is that opening a Google infowindow can cause the map to pan in order for the whole of the infowindow to be visible in the viewport and not obscured by any of the controls. The pan motion can cause the marker to move out from underneath the mouse, causing a mouseout. One way to deal with that effect is to use the undocumented {suppressMapPan:true} option on your infowindow. Another way to deal with it is to use a non-Google infowindow that doesn't pan the map.
Another thing that can happen is that you might have an incorrectly designed custom GIcon. If the .infoWIndowAnchor is too low, the infowindow itself could steal the mouseover, causing a mouseout on the marker. You can deal with that by setting the y coordinate of the .infoWindowAnchor more negative.
However, when you get it all working, you'll probably find that a map that opens the infowindow on marker mouseover is awkward to use. You get a better user interface, and one that some users will already be familiar with, by only displaying a small tooltip on mouseover, and only displaying the full infowindow when the marker is clicked.
It happens in other areas of JavaScript/HTML also.
Sometimes you have to bind a handler to an event but only after handled the current one because it gets called immediately...
So instead of
GEvent.addListener(...);
I do
setTimeout(function() { GEvent.addListener(...); }, 1);
To give the current thread the time to finish up handling the current event.
Hope this helps.