diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c8d32ee..067a3c42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Fix `Konva.Label` position when tag attributes are changed - Fix incorrect ellipsis display for `Konva.Text` +- Fix `click` event trigger on parent containers on touch devices ### 8.3.10 (2022-06-20) diff --git a/src/DragAndDrop.ts b/src/DragAndDrop.ts index f8d7a695..4523601f 100644 --- a/src/DragAndDrop.ts +++ b/src/DragAndDrop.ts @@ -95,6 +95,7 @@ export const DD = { // dragBefore and dragAfter allows us to set correct order of events // setup all in dragbefore, and stop dragging only after pointerup triggered. _endDragBefore(evt?) { + const drawNodes = []; DD._dragElements.forEach((elem) => { const { node } = elem; // we need to find pointer relative to that node @@ -124,10 +125,17 @@ export const DD = { const drawNode = elem.node.getLayer() || ((elem.node instanceof Konva['Stage'] && elem.node) as any); - if (drawNode) { - drawNode.batchDraw(); + + if (drawNode && drawNodes.indexOf(drawNode) === -1) { + drawNodes.push(drawNode); } }); + // draw in a sync way + // because mousemove event may trigger BEFORE batch draw is called + // but as we have not hit canvas updated yet, it will trigger incorrect mouseover/mouseout events + drawNodes.forEach((drawNode) => { + drawNode.draw(); + }); }, _endDragAfter(evt) { DD._dragElements.forEach((elem, key) => { diff --git a/src/Stage.ts b/src/Stage.ts index 16900efe..7dc9fdf3 100644 --- a/src/Stage.ts +++ b/src/Stage.ts @@ -737,7 +737,10 @@ export class Stage extends Container { // always call preventDefault for desktop events because some browsers // try to drag and drop the canvas element - if (evt.cancelable && eventType !== "touch") { + // TODO: are we sure we need to prevent default at all? + // do not call this function on mobile because it prevent "click" event on all parent containers + // but apps may listen to it. + if (evt.cancelable && eventType !== 'touch') { evt.preventDefault(); } } diff --git a/test/unit/DragAndDrop-test.ts b/test/unit/DragAndDrop-test.ts index c8ebaa06..c734fcec 100644 --- a/test/unit/DragAndDrop-test.ts +++ b/test/unit/DragAndDrop-test.ts @@ -1223,4 +1223,60 @@ describe('DragAndDrop', function () { assert.equal(dragstart, 0); assert.equal(dragend, 0); }); + + it('mouseleave should not occur after drag and drop', function (done) { + var stage = addStage(); + var layer = new Konva.Layer(); + var circle = new Konva.Circle({ + x: 40, + y: 40, + radius: 20, + strokeWidth: 4, + fill: 'green', + stroke: 'black', + draggable: true, + }); + layer.add(circle); + stage.add(layer); + var mouseleave = false; + var dragend = false; + var mouseenter = true; + circle.on('mouseenter', function () { + mouseenter = true; + }); + circle.on('mouseleave', function () { + mouseleave = true; + }); + circle.on('dragend', function () { + dragend = true; + }); + simulateMouseMove(stage, { + x: 40, + y: 40, + }); + assert(mouseenter, 'mouseenter event should have been fired'); + simulateMouseDown(stage, { + x: 40, + y: 40, + }); + setTimeout(function () { + simulateMouseMove(stage, { + x: 100, + y: 100, + }); + setTimeout(() => { + simulateMouseUp(stage, { + x: 100, + y: 100, + }); + simulateMouseMove(stage, { + x: 102, + y: 102, + }); + assert(!mouseleave, 'mouseleave event should not have been fired'); + assert(dragend, 'dragend event should have been fired'); + done(); + }, 70); + }, 70); + }); }); diff --git a/test/unit/test-utils.ts b/test/unit/test-utils.ts index d8f85f7c..3738df2e 100644 --- a/test/unit/test-utils.ts +++ b/test/unit/test-utils.ts @@ -202,8 +202,8 @@ export function simulateMouseMove(stage, pos) { type: 'mousemove', }; - stage._pointermove(evt); Konva.DD._drag(evt); + stage._pointermove(evt); } export function simulateMouseUp(stage, pos) {