mirror of
https://github.com/konvajs/konva.git
synced 2025-10-15 12:34:52 +08:00
improved mouseover and mouseout event handling by ignoring parent handlers if mouse moves from one child to another
This commit is contained in:
45
src/Node.js
45
src/Node.js
@@ -531,21 +531,40 @@ Kinetic.Node.prototype = {
|
||||
* @param {Event} evt
|
||||
*/
|
||||
_handleEvents: function(eventType, evt) {
|
||||
// generic events handler
|
||||
function handle(obj) {
|
||||
var el = obj.eventListeners;
|
||||
if(el[eventType]) {
|
||||
var events = el[eventType];
|
||||
for(var i = 0; i < events.length; i++) {
|
||||
events[i].handler.apply(obj, [evt]);
|
||||
}
|
||||
}
|
||||
var stage = this.getStage();
|
||||
this._handleEvent(this, stage.mouseoverShape, stage.mouseoutShape, eventType, evt);
|
||||
},
|
||||
/**
|
||||
* handle node event
|
||||
*/
|
||||
_handleEvent: function(node, mouseoverNode, mouseoutNode, eventType, evt) {
|
||||
var el = node.eventListeners;
|
||||
var okayToRun = true;
|
||||
|
||||
// simulate event bubbling
|
||||
if(!evt.cancelBubble && obj.parent.className !== 'Stage') {
|
||||
handle(obj.parent);
|
||||
/*
|
||||
* determine if event handler should be skipped by comparing
|
||||
* parent nodes
|
||||
*/
|
||||
if(eventType === 'onmouseover' && mouseoutNode && mouseoutNode.id === node.id) {
|
||||
okayToRun = false;
|
||||
}
|
||||
else if(eventType === 'onmouseout' && mouseoverNode && mouseoverNode.id === node.id) {
|
||||
okayToRun = false;
|
||||
}
|
||||
|
||||
if(el[eventType] && okayToRun) {
|
||||
var events = el[eventType];
|
||||
for(var i = 0; i < events.length; i++) {
|
||||
events[i].handler.apply(node, [evt]);
|
||||
}
|
||||
}
|
||||
handle(this);
|
||||
|
||||
var mouseoverParent = mouseoverNode ? mouseoverNode.parent : undefined;
|
||||
var mouseoutParent = mouseoutNode ? mouseoutNode.parent : undefined;
|
||||
|
||||
// simulate event bubbling
|
||||
if(!evt.cancelBubble && node.parent.className !== 'Stage') {
|
||||
this._handleEvent(node.parent, mouseoverParent, mouseoutParent, eventType, evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
61
src/Stage.js
61
src/Stage.js
@@ -21,9 +21,11 @@ Kinetic.Stage = function(cont, width, height) {
|
||||
y: 1
|
||||
};
|
||||
this.dblClickWindow = 400;
|
||||
this.targetShape = undefined;
|
||||
this.clickStart = false;
|
||||
this.targetShape = undefined;
|
||||
this.targetFound = false;
|
||||
this.mouseoverShape = undefined;
|
||||
this.mouseoutShape = undefined;
|
||||
|
||||
// desktop flags
|
||||
this.mousePos = undefined;
|
||||
@@ -338,12 +340,25 @@ Kinetic.Stage.prototype = {
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: these event handlers require target shape
|
||||
* handling
|
||||
*/
|
||||
* NOTE: these event handlers require target shape
|
||||
* handling
|
||||
*/
|
||||
|
||||
// handle onmouseover
|
||||
else if(!isDragging && this._isNewTarget(shape, evt)) {
|
||||
// handle onmouseover
|
||||
/*
|
||||
* check to see if there are stored mouseout events first.
|
||||
* if there are, run those before running the onmouseover
|
||||
* events
|
||||
*/
|
||||
if(this.mouseoutShape) {
|
||||
this.mouseoverShape = shape;
|
||||
this.mouseoutShape._handleEvents('onmouseout', evt);
|
||||
this.mouseoverShape = undefined;
|
||||
}
|
||||
|
||||
shape._handleEvents('onmouseover', evt);
|
||||
this._setTarget(shape);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -356,13 +371,24 @@ Kinetic.Stage.prototype = {
|
||||
}
|
||||
// handle mouseout condition
|
||||
else if(!isDragging && this.targetShape && this.targetShape.id === shape.id) {
|
||||
this.targetShape = undefined;
|
||||
shape._handleEvents('onmouseout', evt);
|
||||
this._setTarget(undefined);
|
||||
this.mouseoutShape = shape;
|
||||
//shape._handleEvents('onmouseout', evt);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* set new target
|
||||
*/
|
||||
_setTarget: function(shape) {
|
||||
this.targetShape = shape;
|
||||
this.targetFound = true;
|
||||
},
|
||||
/**
|
||||
* check if shape should be a new target
|
||||
*/
|
||||
_isNewTarget: function(shape, evt) {
|
||||
if(!this.targetShape || (!this.targetFound && shape.id !== this.targetShape.id)) {
|
||||
/*
|
||||
@@ -371,14 +397,10 @@ Kinetic.Stage.prototype = {
|
||||
if(this.targetShape) {
|
||||
var oldEl = this.targetShape.eventListeners;
|
||||
if(oldEl) {
|
||||
this.targetShape._handleEvents('onmouseout', evt);
|
||||
this.mouseoutShape = this.targetShape;
|
||||
//this.targetShape._handleEvents('onmouseout', evt);
|
||||
}
|
||||
}
|
||||
|
||||
// set new target shape
|
||||
this.targetShape = shape;
|
||||
this.targetFound = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -432,15 +454,26 @@ Kinetic.Stage.prototype = {
|
||||
* three nested loops
|
||||
*/
|
||||
this.targetFound = false;
|
||||
|
||||
var shapeDetected = false;
|
||||
for(var n = this.children.length - 1; n >= 0; n--) {
|
||||
var layer = this.children[n];
|
||||
if(layer.visible && n >= 0 && layer.isListening) {
|
||||
if(this._traverseChildren(layer, evt)) {
|
||||
n = -1;
|
||||
shapeDetected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if no shape was detected and a mouseout shape has been stored,
|
||||
* then run the onmouseout event handlers
|
||||
*/
|
||||
if(!shapeDetected && this.mouseoutShape) {
|
||||
this.mouseoutShape._handleEvents('onmouseout', evt);
|
||||
this.mouseoutShape = undefined;
|
||||
|
||||
}
|
||||
},
|
||||
/**
|
||||
* begin listening for events by adding event handlers
|
||||
|
Reference in New Issue
Block a user