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++) {
|
for (var i = 0, latlngs = [], len = route.length; i < len; i++) {
|
||||||
latlngs.push(new L.LatLng(route[i][0], route[i][1]));
|
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]});
|
var map = new L.Map('map', {layers: [osm]});
|
||||||
|
|
||||||
@ -41,7 +42,8 @@
|
|||||||
circleOptions = {
|
circleOptions = {
|
||||||
color: 'red',
|
color: 'red',
|
||||||
fillColor: 'yellow',
|
fillColor: 'yellow',
|
||||||
fillOpacity: 0.7
|
fillOpacity: 0.7,
|
||||||
|
renderer: canvas
|
||||||
};
|
};
|
||||||
|
|
||||||
var circle = new L.Circle(circleLocation, 500000, circleOptions),
|
var circle = new L.Circle(circleLocation, 500000, circleOptions),
|
||||||
@ -79,7 +81,8 @@
|
|||||||
|
|
||||||
var polygon = new L.Polygon([polygonPoints, holePoints], {
|
var polygon = new L.Polygon([polygonPoints, holePoints], {
|
||||||
fillColor: "#333",
|
fillColor: "#333",
|
||||||
color: 'green'
|
color: 'green',
|
||||||
|
renderer: canvas
|
||||||
});
|
});
|
||||||
group.addLayer(polygon);
|
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) {
|
if (e.stopPropagation) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
} else if (e.originalEvent) { // In case of Leaflet event.
|
||||||
|
e.originalEvent._stopped = true;
|
||||||
} else {
|
} else {
|
||||||
e.cancelBubble = true;
|
e.cancelBubble = true;
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ L.Canvas = L.Renderer.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_fireEvent: function (layer, e, type) {
|
_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
|
// TODO _bringToFront & _bringToBack, pretty tricky
|
||||||
|
@ -601,6 +601,7 @@ L.Map = L.Evented.extend({
|
|||||||
if (!L.DomEvent) { return; }
|
if (!L.DomEvent) { return; }
|
||||||
|
|
||||||
this._targets = {};
|
this._targets = {};
|
||||||
|
this._targets[L.stamp(this._container)] = this;
|
||||||
|
|
||||||
var onOff = remove ? 'off' : 'on';
|
var onOff = remove ? 'off' : 'on';
|
||||||
|
|
||||||
@ -623,62 +624,81 @@ L.Map = L.Evented.extend({
|
|||||||
this._container.scrollLeft = 0;
|
this._container.scrollLeft = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
_findEventTarget: function (src) {
|
_findEventTargets: function (src, bubble) {
|
||||||
|
var targets = [], target;
|
||||||
while (src) {
|
while (src) {
|
||||||
var target = this._targets[L.stamp(src)];
|
target = this._targets[L.stamp(src)];
|
||||||
if (target) {
|
if (target) {
|
||||||
return target;
|
targets.push(target);
|
||||||
|
if (!bubble) { break; }
|
||||||
}
|
}
|
||||||
if (src === this._container) {
|
if (src === this._container) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
src = src.parentNode;
|
src = src.parentNode;
|
||||||
}
|
}
|
||||||
return null;
|
return targets;
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleDOMEvent: function (e) {
|
_handleDOMEvent: function (e) {
|
||||||
if (!this._loaded || L.DomEvent._skipped(e)) { return; }
|
if (!this._loaded || L.DomEvent._skipped(e)) { return; }
|
||||||
|
|
||||||
// find the layer the event is propagating from
|
// find the layer the event is propagating from and its parents
|
||||||
var target = this._findEventTarget(e.target || e.srcElement),
|
var type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;
|
||||||
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 (e.type === 'click') {
|
||||||
if (!target && (type === 'mouseover' || type === 'mouseout') &&
|
// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
|
||||||
!L.DomEvent._checkMouse(this._container, e)) { return; }
|
var synth = L.Util.extend({}, e);
|
||||||
|
synth.type = 'preclick';
|
||||||
|
this._handleDOMEvent(synth);
|
||||||
|
}
|
||||||
|
|
||||||
// prevents outline when clicking on keyboard-focusable element
|
|
||||||
if (type === 'mousedown') {
|
if (type === 'mousedown') {
|
||||||
|
// prevents outline when clicking on keyboard-focusable element
|
||||||
L.DomUtil.preventOutline(e.target || e.srcElement);
|
L.DomUtil.preventOutline(e.target || e.srcElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._fireDOMEvent(target || this, e, type);
|
this._fireDOMEvent(e, type);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fireDOMEvent: function (target, e, type) {
|
_fireDOMEvent: function (e, type, targets) {
|
||||||
if (!target.listens(type, true) && (type !== 'click' || !target.listens('preclick', true))) { return; }
|
|
||||||
|
|
||||||
if (type === 'contextmenu') {
|
if (type === 'contextmenu') {
|
||||||
L.DomEvent.preventDefault(e);
|
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
|
// prevents firing click after you just dragged an object
|
||||||
if (e.type === 'click' && !e._simulated && this._draggableMoved(target)) { return; }
|
if (e.type === 'click' && !e._simulated && this._draggableMoved(target)) { return; }
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
originalEvent: e
|
originalEvent: e
|
||||||
};
|
};
|
||||||
|
|
||||||
if (e.type !== 'keypress') {
|
if (e.type !== 'keypress') {
|
||||||
data.containerPoint = target instanceof L.Marker ?
|
data.containerPoint = target instanceof L.Marker ?
|
||||||
this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
|
this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
|
||||||
data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
|
data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
|
||||||
data.latlng = this.layerPointToLatLng(data.layerPoint);
|
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) {
|
_draggableMoved: function (obj) {
|
||||||
|
Loading…
Reference in New Issue
Block a user