Leaflet/spec/suites/layer/vector/CanvasSpec.js
ghybs 34dca3cfd9 Fix #5011 (canvas remove+add) (#5024)
Bug when using map option `preferCanvas: true` (canvas renderer for paths) and removing then adding back a vector within the same animation frame (typically in the same sequence, as done by Leaflet.markercluster at `"zoomend"` event, to remove layers and clusters outside visible bounds).
This commit clears the `_removed` flag from paths when they are added to the canvas.
Also added corresponding test suites.
2016-10-20 15:50:15 +03:00

193 lines
5.5 KiB
JavaScript

describe('Canvas', function () {
var c, map, p2ll, latLngs;
before(function () {
c = document.createElement('div');
c.style.width = '400px';
c.style.height = '400px';
c.style.position = 'absolute';
c.style.top = '0';
c.style.left = '0';
document.body.appendChild(c);
map = new L.Map(c, {preferCanvas: true, zoomControl: false});
map.setView([0, 0], 6);
p2ll = function (x, y) {
return map.layerPointToLatLng([x, y]);
};
latLngs = [p2ll(0, 0), p2ll(0, 100), p2ll(100, 100), p2ll(100, 0)];
});
after(function () {
document.body.removeChild(c);
});
describe("#events", function () {
var layer;
beforeEach(function () {
layer = L.polygon(latLngs).addTo(map);
});
afterEach(function () {
layer.remove();
});
it("should fire event when layer contains mouse", function () {
var spy = sinon.spy();
layer.on('click', spy);
happen.at('click', 50, 50); // Click on the layer.
expect(spy.callCount).to.eql(1);
happen.at('click', 150, 150); // Click outside layer.
expect(spy.callCount).to.eql(1);
layer.off("click", spy);
});
it("DOM events propagate from canvas polygon to map", function () {
var spy = sinon.spy();
map.on("click", spy);
happen.at('click', 50, 50);
expect(spy.callCount).to.eql(1);
map.off("click", spy);
});
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("click", mapSpy);
layer.on("click", L.DomEvent.stopPropagation).on("click", layerSpy);
happen.at('click', 50, 50);
expect(layerSpy.callCount).to.eql(1);
expect(mapSpy.callCount).to.eql(0);
map.off("click", mapSpy);
layer.off("click", L.DomEvent.stopPropagation).off("click", layerSpy);
});
it("DOM events fired on canvas polygon are propagated only once to the map even when two layers contains the event", function () {
var spy = sinon.spy();
var layer2 = L.polygon(latLngs).addTo(map);
map.on("click", spy);
happen.at('click', 50, 50);
expect(spy.callCount).to.eql(1);
layer2.remove();
map.off("click", spy);
});
it("should fire preclick before click", function () {
var clickSpy = sinon.spy();
var preclickSpy = sinon.spy();
layer.on('click', clickSpy);
layer.on('preclick', preclickSpy);
layer.once('preclick', function (e) {
expect(clickSpy.called).to.be(false);
});
happen.at('click', 50, 50); // Click on the layer.
expect(clickSpy.callCount).to.eql(1);
expect(preclickSpy.callCount).to.eql(1);
happen.at('click', 150, 150); // Click outside layer.
expect(clickSpy.callCount).to.eql(1);
expect(preclickSpy.callCount).to.eql(1);
layer.off();
});
it("should not fire click when dragging the map on top of it", function (done) {
var downSpy = sinon.spy();
var clickSpy = sinon.spy();
var preclickSpy = sinon.spy();
layer.on('click', clickSpy);
layer.on('preclick', preclickSpy);
layer.on('mousedown', downSpy);
var hand = new Hand({
timing: 'fastframe',
onStop: function () {
// Prosthetic does not fire a click when we down+up, but it real world
// browsers would, so let's simulate it.
happen.at('click', 70, 60);
expect(downSpy.called).to.be(true);
expect(clickSpy.called).to.be(false);
expect(preclickSpy.called).to.be(false);
layer.off();
done();
}
});
var mouse = hand.growFinger('mouse');
// We move 5 pixels first to overcome the 3-pixel threshold of
// L.Draggable.
mouse.moveTo(50, 50, 0)
.down().moveBy(20, 10, 200).up();
});
});
describe("#events(interactive=false)", function () {
var layer;
beforeEach(function () {
layer = L.polygon(latLngs, {interactive: false}).addTo(map);
});
afterEach(function () {
layer.remove();
});
it("should not fire click when not interactive", function () {
var spy = sinon.spy();
layer.on('click', spy);
happen.at('click', 50, 50); // Click on the layer.
expect(spy.callCount).to.eql(0);
happen.at('click', 150, 150); // Click outside layer.
expect(spy.callCount).to.eql(0);
layer.off("click", spy);
});
});
describe('#dashArray', function () {
it('can add polyline with dashArray', function () {
var layer = L.polygon(latLngs, {
dashArray: "5,5"
}).addTo(map);
});
it('can setStyle with dashArray', function () {
var layer = L.polygon(latLngs).addTo(map);
layer.setStyle({
dashArray: "5,5"
});
});
});
it('removes vector on next animation frame', function (done) {
var layer = L.circle([0, 0]).addTo(map),
layerId = L.stamp(layer),
canvas = map.getRenderer(layer);
expect(canvas._layers.hasOwnProperty(layerId)).to.be(true);
map.removeLayer(layer);
// Defer check due to how Canvas renderer manages layer removal.
L.Util.requestAnimFrame(function () {
expect(canvas._layers.hasOwnProperty(layerId)).to.be(false);
done();
}, this);
});
it('adds vectors even if they have been removed just before', function (done) {
var layer = L.circle([0, 0]).addTo(map),
layerId = L.stamp(layer),
canvas = map.getRenderer(layer);
expect(canvas._layers.hasOwnProperty(layerId)).to.be(true);
map.removeLayer(layer);
map.addLayer(layer);
expect(canvas._layers.hasOwnProperty(layerId)).to.be(true);
// Re-perform a deferred check due to how Canvas renderer manages layer removal.
L.Util.requestAnimFrame(function () {
expect(canvas._layers.hasOwnProperty(layerId)).to.be(true);
done();
}, this);
});
});