Merge pull request #3307 from Leaflet/map-domevent
Always fire DOM event on the map too
This commit is contained in:
commit
62c71f5c1f
107
debug/tests/mousemove_on_polygons.html
Normal file
107
debug/tests/mousemove_on_polygons.html
Normal file
@ -0,0 +1,107 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Leaflet debug page</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
|
||||
<link rel="stylesheet" href="../../dist/leaflet.css" />
|
||||
|
||||
<link rel="stylesheet" href="../css/screen.css" />
|
||||
<style>
|
||||
.mybox {
|
||||
background-color: red;
|
||||
}
|
||||
td {
|
||||
border: transparent solid 2px;
|
||||
}
|
||||
td.red {
|
||||
border: red solid 2px;
|
||||
}
|
||||
td.updated {
|
||||
border: transparent solid 2px;
|
||||
animation-name: borderfade;
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
@keyframes borderfade {
|
||||
from {
|
||||
border: red solid 2px;
|
||||
}
|
||||
to {
|
||||
border: transparent solid 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="../../build/deps.js"></script>
|
||||
<script src="../leaflet-include.js"></script>
|
||||
<table>
|
||||
<tr><td> </td><td>Enter </td><td>Move </td><td>Exit </td><td>Click </td></tr>
|
||||
<tr><td>Triangle 1:</td><td id='enter1'></td><td id='move1'></td><td id='exit1'></td><td id='click1'></td></tr>
|
||||
<tr><td>Triangle 2:</td><td id='enter2'></td><td id='move2'></td><td id='exit2'></td><td id='click2'></td></tr>
|
||||
<tr><td>Map: </td><td id='enter3'></td><td id='move3'></td><td id='exit3'></td><td id='click3'></td></tr>
|
||||
</table>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
osmAttrib = '© <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
osm = L.tileLayer(osmUrl, {maxZoom: 18, attribution: osmAttrib}),
|
||||
latlng = new L.LatLng(39.05, 8.40);
|
||||
|
||||
var map = new L.Map('map', {center: latlng, zoom: 12, layers: [osm]});
|
||||
|
||||
function update(domid) {
|
||||
return function(){
|
||||
document.getElementById(domid).innerHTML = Date.now();
|
||||
document.getElementById(domid).className = 'red';
|
||||
window.setTimeout(function(){
|
||||
document.getElementById(domid).className = 'updated';
|
||||
},1);
|
||||
}
|
||||
}
|
||||
|
||||
var polygon = (new L.Polygon([
|
||||
[39, 8.40],
|
||||
[39.10, 8.50],
|
||||
[39.05, 8.30]
|
||||
])).addTo(map).on('mouseover',update('enter1'))
|
||||
.on('mousemove',update('move1'))
|
||||
.on('mouseout',update('exit1'))
|
||||
.on('click',update('click1'))
|
||||
.bindPopup('Triangle 1');
|
||||
|
||||
var polygon2 = (new L.Polygon([
|
||||
[39.03, 8.30],
|
||||
[39.10, 8.40],
|
||||
[39.00, 8.30]
|
||||
])).addTo(map).on('mouseover',update('enter2'))
|
||||
.on('mousemove',update('move2'))
|
||||
.on('mouseout',update('exit2'))
|
||||
.on('click',update('click2'))
|
||||
.bindPopup('Triangle 2');
|
||||
|
||||
|
||||
var marker = new L.Marker(latlng, {draggable: true})
|
||||
.bindPopup('Marker');;
|
||||
map.addLayer(marker);
|
||||
|
||||
|
||||
// map.on('mousemove', function (e) {
|
||||
// marker.setLatLng(e.latlng);
|
||||
// });
|
||||
map.on('mouseover',update('enter3'))
|
||||
.on('mousemove',update('move3'))
|
||||
.on('mouseout',update('exit3'))
|
||||
.on('click',update('click3'));
|
||||
|
||||
// We should be able to move marker around in a fluid way,
|
||||
// plus going over the polygon with no issue.
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -29,7 +29,8 @@
|
||||
for (var i = 0, latlngs = [], len = route.length; i < len; i++) {
|
||||
latlngs.push(new L.LatLng(route[i][0], route[i][1]));
|
||||
}
|
||||
var path = new L.Polyline(latlngs);
|
||||
var canvas = L.canvas();
|
||||
var path = new L.Polyline(latlngs, {renderer: canvas});
|
||||
|
||||
var map = new L.Map('map', {layers: [osm]});
|
||||
|
||||
@ -41,7 +42,8 @@
|
||||
circleOptions = {
|
||||
color: 'red',
|
||||
fillColor: 'yellow',
|
||||
fillOpacity: 0.7
|
||||
fillOpacity: 0.7,
|
||||
renderer: canvas
|
||||
};
|
||||
|
||||
var circle = new L.Circle(circleLocation, 500000, circleOptions),
|
||||
@ -79,7 +81,8 @@
|
||||
|
||||
var polygon = new L.Polygon([polygonPoints, holePoints], {
|
||||
fillColor: "#333",
|
||||
color: 'green'
|
||||
color: 'green',
|
||||
renderer: canvas
|
||||
});
|
||||
group.addLayer(polygon);
|
||||
|
||||
|
@ -619,4 +619,132 @@ describe("Map", function () {
|
||||
|
||||
});
|
||||
|
||||
describe('#DOM events', function () {
|
||||
|
||||
var c, map;
|
||||
|
||||
beforeEach(function () {
|
||||
c = document.createElement('div');
|
||||
c.style.width = '400px';
|
||||
c.style.height = '400px';
|
||||
map = new L.Map(c);
|
||||
map.setView(new L.LatLng(0, 0), 0);
|
||||
document.body.appendChild(c);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
document.body.removeChild(c);
|
||||
});
|
||||
|
||||
it("DOM events propagate from polygon to map", function () {
|
||||
var spy = sinon.spy();
|
||||
map.on("mousemove", spy);
|
||||
var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);
|
||||
happen.mousemove(layer._path);
|
||||
expect(spy.calledOnce).to.be.ok();
|
||||
});
|
||||
|
||||
it("DOM events propagate from canvas polygon to map", function () {
|
||||
var spy = sinon.spy();
|
||||
map.on("mousemove", spy);
|
||||
var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]], {rendered: L.canvas()}).addTo(map);
|
||||
happen.mousemove(layer._path);
|
||||
expect(spy.calledOnce).to.be.ok();
|
||||
});
|
||||
|
||||
it("DOM events propagate from marker to map", function () {
|
||||
var spy = sinon.spy();
|
||||
map.on("mousemove", spy);
|
||||
var layer = new L.Marker([1, 2]).addTo(map);
|
||||
happen.mousemove(layer._icon);
|
||||
expect(spy.calledOnce).to.be.ok();
|
||||
});
|
||||
|
||||
it("DOM events fired on marker can be cancelled before being caught by the map", function () {
|
||||
var mapSpy = sinon.spy();
|
||||
var layerSpy = sinon.spy();
|
||||
map.on("mousemove", mapSpy);
|
||||
var layer = new L.Marker([1, 2]).addTo(map);
|
||||
layer.on("mousemove", L.DomEvent.stopPropagation).on("mousemove", layerSpy);
|
||||
happen.mousemove(layer._icon);
|
||||
expect(layerSpy.calledOnce).to.be.ok();
|
||||
expect(mapSpy.called).not.to.be.ok();
|
||||
});
|
||||
|
||||
it("DOM events fired on polygon can be cancelled before being caught by the map", function () {
|
||||
var mapSpy = sinon.spy();
|
||||
var layerSpy = sinon.spy();
|
||||
map.on("mousemove", mapSpy);
|
||||
var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);
|
||||
layer.on("mousemove", L.DomEvent.stopPropagation).on("mousemove", layerSpy);
|
||||
happen.mousemove(layer._path);
|
||||
expect(layerSpy.calledOnce).to.be.ok();
|
||||
expect(mapSpy.called).not.to.be.ok();
|
||||
});
|
||||
|
||||
it("DOM events fired on canvas polygon can be cancelled before being caught by the map", function () {
|
||||
var mapSpy = sinon.spy();
|
||||
var layerSpy = sinon.spy();
|
||||
map.on("mousemove", mapSpy);
|
||||
var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]], {rendered: L.canvas()}).addTo(map);
|
||||
layer.on("mousemove", L.DomEvent.stopPropagation).on("mousemove", layerSpy);
|
||||
happen.mousemove(layer._path);
|
||||
expect(layerSpy.calledOnce).to.be.ok();
|
||||
expect(mapSpy.called).not.to.be.ok();
|
||||
});
|
||||
|
||||
it("mouseout is only forwared if fired on the original target", function () {
|
||||
var mapSpy = sinon.spy(),
|
||||
layerSpy = sinon.spy(),
|
||||
otherSpy = sinon.spy();
|
||||
var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);
|
||||
var other = new L.Polygon([[10, 20], [30, 40], [50, 60]]).addTo(map);
|
||||
map.on("mouseout", mapSpy);
|
||||
layer.on("mouseout", layerSpy);
|
||||
other.on("mouseout", otherSpy);
|
||||
happen.mouseout(layer._path);
|
||||
expect(mapSpy.called).not.to.be.ok();
|
||||
expect(otherSpy.called).not.to.be.ok();
|
||||
expect(layerSpy.calledOnce).to.be.ok();
|
||||
});
|
||||
|
||||
it("mouseout is not forwared to layers if fired on the map", function () {
|
||||
var mapSpy = sinon.spy(),
|
||||
layerSpy = sinon.spy(),
|
||||
otherSpy = sinon.spy();
|
||||
var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);
|
||||
var other = new L.Polygon([[10, 20], [30, 40], [50, 60]]).addTo(map);
|
||||
map.on("mouseout", mapSpy);
|
||||
layer.on("mouseout", layerSpy);
|
||||
other.on("mouseout", otherSpy);
|
||||
happen.mouseout(map._container);
|
||||
expect(otherSpy.called).not.to.be.ok();
|
||||
expect(layerSpy.called).not.to.be.ok();
|
||||
expect(mapSpy.calledOnce).to.be.ok();
|
||||
});
|
||||
|
||||
it("preclick is fired before click on marker and map", function () {
|
||||
var called = 0;
|
||||
var layer = new L.Marker([1, 2]).addTo(map);
|
||||
layer.on("preclick", function (e) {
|
||||
expect(called++).to.eql(0);
|
||||
expect(e.latlng).to.ok();
|
||||
});
|
||||
layer.on("click", function (e) {
|
||||
expect(called++).to.eql(2);
|
||||
expect(e.latlng).to.ok();
|
||||
});
|
||||
map.on("preclick", function (e) {
|
||||
expect(called++).to.eql(1);
|
||||
expect(e.latlng).to.ok();
|
||||
});
|
||||
map.on("click", function (e) {
|
||||
expect(called++).to.eql(3);
|
||||
expect(e.latlng).to.ok();
|
||||
});
|
||||
happen.click(layer._icon);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -130,6 +130,8 @@ L.DomEvent = {
|
||||
|
||||
if (e.stopPropagation) {
|
||||
e.stopPropagation();
|
||||
} else if (e.originalEvent) { // In case of Leaflet event.
|
||||
e.originalEvent._stopped = true;
|
||||
} else {
|
||||
e.cancelBubble = true;
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ L.Canvas = L.Renderer.extend({
|
||||
},
|
||||
|
||||
_fireEvent: function (layer, e, type) {
|
||||
this._map._fireDOMEvent(layer, e, type || e.type);
|
||||
this._map._fireDOMEvent(e, type || e.type, [layer]);
|
||||
},
|
||||
|
||||
// TODO _bringToFront & _bringToBack, pretty tricky
|
||||
|
@ -601,6 +601,7 @@ L.Map = L.Evented.extend({
|
||||
if (!L.DomEvent) { return; }
|
||||
|
||||
this._targets = {};
|
||||
this._targets[L.stamp(this._container)] = this;
|
||||
|
||||
var onOff = remove ? 'off' : 'on';
|
||||
|
||||
@ -623,62 +624,81 @@ L.Map = L.Evented.extend({
|
||||
this._container.scrollLeft = 0;
|
||||
},
|
||||
|
||||
_findEventTarget: function (src) {
|
||||
_findEventTargets: function (src, bubble) {
|
||||
var targets = [], target;
|
||||
while (src) {
|
||||
var target = this._targets[L.stamp(src)];
|
||||
target = this._targets[L.stamp(src)];
|
||||
if (target) {
|
||||
return target;
|
||||
targets.push(target);
|
||||
if (!bubble) { break; }
|
||||
}
|
||||
if (src === this._container) {
|
||||
break;
|
||||
}
|
||||
src = src.parentNode;
|
||||
}
|
||||
return null;
|
||||
return targets;
|
||||
},
|
||||
|
||||
_handleDOMEvent: function (e) {
|
||||
if (!this._loaded || L.DomEvent._skipped(e)) { return; }
|
||||
|
||||
// find the layer the event is propagating from
|
||||
var target = this._findEventTarget(e.target || e.srcElement),
|
||||
type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;
|
||||
// find the layer the event is propagating from and its parents
|
||||
var type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;
|
||||
|
||||
// special case for map mouseover/mouseout events so that they're actually mouseenter/mouseleave
|
||||
if (!target && (type === 'mouseover' || type === 'mouseout') &&
|
||||
!L.DomEvent._checkMouse(this._container, e)) { return; }
|
||||
if (e.type === 'click') {
|
||||
// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
|
||||
var synth = L.Util.extend({}, e);
|
||||
synth.type = 'preclick';
|
||||
this._handleDOMEvent(synth);
|
||||
}
|
||||
|
||||
// prevents outline when clicking on keyboard-focusable element
|
||||
if (type === 'mousedown') {
|
||||
// prevents outline when clicking on keyboard-focusable element
|
||||
L.DomUtil.preventOutline(e.target || e.srcElement);
|
||||
}
|
||||
|
||||
this._fireDOMEvent(target || this, e, type);
|
||||
this._fireDOMEvent(e, type);
|
||||
},
|
||||
|
||||
_fireDOMEvent: function (target, e, type) {
|
||||
if (!target.listens(type, true) && (type !== 'click' || !target.listens('preclick', true))) { return; }
|
||||
_fireDOMEvent: function (e, type, targets) {
|
||||
|
||||
if (type === 'contextmenu') {
|
||||
L.DomEvent.preventDefault(e);
|
||||
}
|
||||
|
||||
var isHover = type === 'mouseover' || type === 'mouseout';
|
||||
targets = (targets || []).concat(this._findEventTargets(e.target || e.srcElement, !isHover));
|
||||
|
||||
if (!targets.length) {
|
||||
targets = [this];
|
||||
|
||||
// special case for map mouseover/mouseout events so that they're actually mouseenter/mouseleave
|
||||
if (isHover && !L.DomEvent._checkMouse(this._container, e)) { return; }
|
||||
}
|
||||
|
||||
var target = targets[0];
|
||||
|
||||
// prevents firing click after you just dragged an object
|
||||
if (e.type === 'click' && !e._simulated && this._draggableMoved(target)) { return; }
|
||||
|
||||
var data = {
|
||||
originalEvent: e
|
||||
};
|
||||
|
||||
if (e.type !== 'keypress') {
|
||||
data.containerPoint = target instanceof L.Marker ?
|
||||
this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
|
||||
data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
|
||||
data.latlng = this.layerPointToLatLng(data.layerPoint);
|
||||
}
|
||||
if (type === 'click') {
|
||||
target.fire('preclick', data, true);
|
||||
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
if (targets[i].listens(type, true)) {
|
||||
targets[i].fire(type, data, true);
|
||||
if (data.originalEvent._stopped) { return; }
|
||||
}
|
||||
}
|
||||
target.fire(type, data, true);
|
||||
},
|
||||
|
||||
_draggableMoved: function (obj) {
|
||||
|
Loading…
Reference in New Issue
Block a user