mirror of
https://github.com/konvajs/konva.git
synced 2025-09-18 09:50:05 +08:00
hit detection color mapping now takes into account anti-aliasing color variations, which was causing issues when moving the mouse from one shape into another shape which were inside the same group. created getIntersections() method which returns an object with shape and pixel data
This commit is contained in:
136
dist/kinetic-core.js
vendored
136
dist/kinetic-core.js
vendored
@@ -3062,6 +3062,47 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* get intersection object that contains shape and pixel data
|
||||
* @name getIntersection
|
||||
* @methodOf Kinetic.Stage.prototype
|
||||
* @param {Object} pos point object
|
||||
*/
|
||||
getIntersection: function(pos) {
|
||||
var shape;
|
||||
var layers = this.getChildren();
|
||||
|
||||
/*
|
||||
* traverse through layers from top to bottom and look
|
||||
* for hit detection
|
||||
*/
|
||||
for(var n = layers.length - 1; n >= 0; n--) {
|
||||
var layer = layers[n];
|
||||
var p = layer.bufferCanvas.context.getImageData(pos.x, pos.y, 1, 1).data;
|
||||
// this indicates that a buffer pixel may have been found
|
||||
if(p[3] === 255) {
|
||||
var colorKey = Kinetic.Type._rgbToHex(p[0], p[1], p[2]);
|
||||
shape = Kinetic.Global.shapes[colorKey];
|
||||
var isDragging = Kinetic.Global.drag.moving;
|
||||
|
||||
return {
|
||||
shape: shape,
|
||||
pixels: p
|
||||
};
|
||||
}
|
||||
// if no shape mapped to that pixel, return pixel array
|
||||
else if(p[0] > 0 || p[1] > 0 || p[2] > 0 || p[3] > 0) {
|
||||
return {
|
||||
pixels: p
|
||||
};
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
_resizeDOM: function() {
|
||||
var width = this.attrs.width;
|
||||
var height = this.attrs.height;
|
||||
@@ -3107,31 +3148,6 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
layer.draw();
|
||||
this.content.appendChild(layer.canvas.element);
|
||||
},
|
||||
_getIntersectingShape: function() {
|
||||
var pos = this.getUserPosition();
|
||||
var shape;
|
||||
var layers = this.getChildren();
|
||||
|
||||
/*
|
||||
* traverse through layers from top to bottom and look
|
||||
* for hit detection
|
||||
*/
|
||||
for(var n = layers.length - 1; n >= 0; n--) {
|
||||
var layer = layers[n];
|
||||
var p = layer.bufferCanvas.context.getImageData(pos.x, pos.y, 1, 1).data;
|
||||
if(p[3] === 255) {
|
||||
var colorKey = Kinetic.Type._rgbToHex(p[0], p[1], p[2]);
|
||||
shape = Kinetic.Global.shapes[colorKey];
|
||||
var isDragging = Kinetic.Global.drag.moving;
|
||||
|
||||
if(shape) {
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
_setUserPosition: function(evt) {
|
||||
if(!evt) {
|
||||
evt = window.event;
|
||||
@@ -3173,18 +3189,24 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._endDrag(evt);
|
||||
},
|
||||
_mousemove: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
var go = Kinetic.Global;
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
if(!go.drag.moving && (!this.targetShape || this.targetShape._id !== shape._id)) {
|
||||
if(this.targetShape) {
|
||||
this.targetShape._handleEvent('mouseout', evt, shape);
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
|
||||
if(obj) {
|
||||
var shape = obj.shape;
|
||||
if(shape) {
|
||||
if(!go.drag.moving && obj.pixels[3] === 255 && (!this.targetShape || this.targetShape._id !== shape._id)) {
|
||||
if(this.targetShape) {
|
||||
this.targetShape._handleEvent('mouseout', evt, shape);
|
||||
}
|
||||
shape._handleEvent('mouseover', evt, this.targetShape);
|
||||
this.targetShape = shape;
|
||||
}
|
||||
else {
|
||||
shape._handleEvent('mousemove', evt);
|
||||
}
|
||||
shape._handleEvent('mouseover', evt, this.targetShape);
|
||||
this.targetShape = shape;
|
||||
}
|
||||
shape._handleEvent('mousemove', evt);
|
||||
}
|
||||
/*
|
||||
* if no shape was detected, clear target shape and try
|
||||
@@ -3199,9 +3221,10 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._startDrag(evt);
|
||||
},
|
||||
_mousedown: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
this._setUserPosition(evt);
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
this.clickStart = true;
|
||||
shape._handleEvent('mousedown', evt);
|
||||
}
|
||||
@@ -3212,11 +3235,12 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
}
|
||||
},
|
||||
_mouseup: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
var go = Kinetic.Global;
|
||||
var shape = this._getIntersectingShape();
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
var that = this;
|
||||
if(shape) {
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
shape._handleEvent('mouseup', evt);
|
||||
|
||||
// detect if click or double click occurred
|
||||
@@ -3244,10 +3268,12 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._endDrag(evt);
|
||||
},
|
||||
_touchstart: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
evt.preventDefault();
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
this.tapStart = true;
|
||||
shape._handleEvent('touchstart', evt);
|
||||
}
|
||||
@@ -3260,11 +3286,12 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
}
|
||||
},
|
||||
_touchend: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
var go = Kinetic.Global;
|
||||
var shape = this._getIntersectingShape();
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
var that = this;
|
||||
if(shape) {
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
shape._handleEvent('touchend', evt);
|
||||
|
||||
// detect if tap or double tap occurred
|
||||
@@ -3293,10 +3320,11 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._endDrag(evt);
|
||||
},
|
||||
_touchmove: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
evt.preventDefault();
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
shape._handleEvent('touchmove', evt);
|
||||
}
|
||||
|
||||
@@ -3495,19 +3523,9 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this.nodeType = 'Stage';
|
||||
this.dblClickWindow = 400;
|
||||
this.targetShape = null;
|
||||
|
||||
// desktop flags
|
||||
this.mousePos = undefined;
|
||||
this.mouseDown = false;
|
||||
this.mouseUp = false;
|
||||
this.mouseMove = false;
|
||||
this.clickStart = false;
|
||||
|
||||
// mobile flags
|
||||
this.touchPos = undefined;
|
||||
this.touchStart = false;
|
||||
this.touchEnd = false;
|
||||
this.touchMove = false;
|
||||
this.tapStart = false;
|
||||
|
||||
this.ids = {};
|
||||
|
4
dist/kinetic-core.min.js
vendored
4
dist/kinetic-core.min.js
vendored
File diff suppressed because one or more lines are too long
136
src/Stage.js
136
src/Stage.js
@@ -344,6 +344,47 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* get intersection object that contains shape and pixel data
|
||||
* @name getIntersection
|
||||
* @methodOf Kinetic.Stage.prototype
|
||||
* @param {Object} pos point object
|
||||
*/
|
||||
getIntersection: function(pos) {
|
||||
var shape;
|
||||
var layers = this.getChildren();
|
||||
|
||||
/*
|
||||
* traverse through layers from top to bottom and look
|
||||
* for hit detection
|
||||
*/
|
||||
for(var n = layers.length - 1; n >= 0; n--) {
|
||||
var layer = layers[n];
|
||||
var p = layer.bufferCanvas.context.getImageData(pos.x, pos.y, 1, 1).data;
|
||||
// this indicates that a buffer pixel may have been found
|
||||
if(p[3] === 255) {
|
||||
var colorKey = Kinetic.Type._rgbToHex(p[0], p[1], p[2]);
|
||||
shape = Kinetic.Global.shapes[colorKey];
|
||||
var isDragging = Kinetic.Global.drag.moving;
|
||||
|
||||
return {
|
||||
shape: shape,
|
||||
pixels: p
|
||||
};
|
||||
}
|
||||
// if no shape mapped to that pixel, return pixel array
|
||||
else if(p[0] > 0 || p[1] > 0 || p[2] > 0 || p[3] > 0) {
|
||||
return {
|
||||
pixels: p
|
||||
};
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
_resizeDOM: function() {
|
||||
var width = this.attrs.width;
|
||||
var height = this.attrs.height;
|
||||
@@ -389,31 +430,6 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
layer.draw();
|
||||
this.content.appendChild(layer.canvas.element);
|
||||
},
|
||||
_getIntersectingShape: function() {
|
||||
var pos = this.getUserPosition();
|
||||
var shape;
|
||||
var layers = this.getChildren();
|
||||
|
||||
/*
|
||||
* traverse through layers from top to bottom and look
|
||||
* for hit detection
|
||||
*/
|
||||
for(var n = layers.length - 1; n >= 0; n--) {
|
||||
var layer = layers[n];
|
||||
var p = layer.bufferCanvas.context.getImageData(pos.x, pos.y, 1, 1).data;
|
||||
if(p[3] === 255) {
|
||||
var colorKey = Kinetic.Type._rgbToHex(p[0], p[1], p[2]);
|
||||
shape = Kinetic.Global.shapes[colorKey];
|
||||
var isDragging = Kinetic.Global.drag.moving;
|
||||
|
||||
if(shape) {
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
_setUserPosition: function(evt) {
|
||||
if(!evt) {
|
||||
evt = window.event;
|
||||
@@ -455,18 +471,24 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._endDrag(evt);
|
||||
},
|
||||
_mousemove: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
var go = Kinetic.Global;
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
if(!go.drag.moving && (!this.targetShape || this.targetShape._id !== shape._id)) {
|
||||
if(this.targetShape) {
|
||||
this.targetShape._handleEvent('mouseout', evt, shape);
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
|
||||
if(obj) {
|
||||
var shape = obj.shape;
|
||||
if(shape) {
|
||||
if(!go.drag.moving && obj.pixels[3] === 255 && (!this.targetShape || this.targetShape._id !== shape._id)) {
|
||||
if(this.targetShape) {
|
||||
this.targetShape._handleEvent('mouseout', evt, shape);
|
||||
}
|
||||
shape._handleEvent('mouseover', evt, this.targetShape);
|
||||
this.targetShape = shape;
|
||||
}
|
||||
else {
|
||||
shape._handleEvent('mousemove', evt);
|
||||
}
|
||||
shape._handleEvent('mouseover', evt, this.targetShape);
|
||||
this.targetShape = shape;
|
||||
}
|
||||
shape._handleEvent('mousemove', evt);
|
||||
}
|
||||
/*
|
||||
* if no shape was detected, clear target shape and try
|
||||
@@ -481,9 +503,10 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._startDrag(evt);
|
||||
},
|
||||
_mousedown: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
this._setUserPosition(evt);
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
this.clickStart = true;
|
||||
shape._handleEvent('mousedown', evt);
|
||||
}
|
||||
@@ -494,11 +517,12 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
}
|
||||
},
|
||||
_mouseup: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
var go = Kinetic.Global;
|
||||
var shape = this._getIntersectingShape();
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
var that = this;
|
||||
if(shape) {
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
shape._handleEvent('mouseup', evt);
|
||||
|
||||
// detect if click or double click occurred
|
||||
@@ -526,10 +550,12 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._endDrag(evt);
|
||||
},
|
||||
_touchstart: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
evt.preventDefault();
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
this.tapStart = true;
|
||||
shape._handleEvent('touchstart', evt);
|
||||
}
|
||||
@@ -542,11 +568,12 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
}
|
||||
},
|
||||
_touchend: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
var go = Kinetic.Global;
|
||||
var shape = this._getIntersectingShape();
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
var that = this;
|
||||
if(shape) {
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
shape._handleEvent('touchend', evt);
|
||||
|
||||
// detect if tap or double tap occurred
|
||||
@@ -575,10 +602,11 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this._endDrag(evt);
|
||||
},
|
||||
_touchmove: function(evt) {
|
||||
this._setUserPosition(evt);
|
||||
this._setUserPosition(evt);
|
||||
evt.preventDefault();
|
||||
var shape = this._getIntersectingShape();
|
||||
if(shape) {
|
||||
var obj = this.getIntersection(this.getUserPosition());
|
||||
if(obj && obj.shape) {
|
||||
var shape = obj.shape;
|
||||
shape._handleEvent('touchmove', evt);
|
||||
}
|
||||
|
||||
@@ -777,19 +805,9 @@ Kinetic.Stage = Kinetic.Container.extend({
|
||||
this.nodeType = 'Stage';
|
||||
this.dblClickWindow = 400;
|
||||
this.targetShape = null;
|
||||
|
||||
// desktop flags
|
||||
this.mousePos = undefined;
|
||||
this.mouseDown = false;
|
||||
this.mouseUp = false;
|
||||
this.mouseMove = false;
|
||||
this.clickStart = false;
|
||||
|
||||
// mobile flags
|
||||
this.touchPos = undefined;
|
||||
this.touchStart = false;
|
||||
this.touchEnd = false;
|
||||
this.touchMove = false;
|
||||
this.tapStart = false;
|
||||
|
||||
this.ids = {};
|
||||
|
@@ -297,37 +297,37 @@ Test.prototype.tests = {
|
||||
|
||||
circle.on('mousedown', function() {
|
||||
mousedown = true;
|
||||
//log('mousedown');
|
||||
log('mousedown');
|
||||
});
|
||||
|
||||
circle.on('mouseup', function() {
|
||||
mouseup = true;
|
||||
//log('mouseup');
|
||||
log('mouseup');
|
||||
});
|
||||
|
||||
circle.on('mouseover', function() {
|
||||
mouseover = true;
|
||||
//log('mouseover');
|
||||
log('mouseover');
|
||||
});
|
||||
|
||||
circle.on('mouseout', function() {
|
||||
mouseout = true;
|
||||
//log('mouseout');
|
||||
log('mouseout');
|
||||
});
|
||||
|
||||
circle.on('mousemove', function() {
|
||||
mousemove = true;
|
||||
//log('mousemove');
|
||||
log('mousemove');
|
||||
});
|
||||
|
||||
circle.on('click', function() {
|
||||
click = true;
|
||||
//log('click');
|
||||
log('click');
|
||||
});
|
||||
|
||||
circle.on('dblclick', function() {
|
||||
dblclick = true;
|
||||
//log('dblclick');
|
||||
log('dblclick');
|
||||
});
|
||||
/*
|
||||
* mobile
|
||||
@@ -367,7 +367,7 @@ Test.prototype.tests = {
|
||||
});
|
||||
|
||||
test(mouseover, '1) mouseover should be true');
|
||||
test(mousemove, '1) mousemove should be true');
|
||||
test(!mousemove, '1) mousemove should be true');
|
||||
test(!mousedown, '1) mousedown should be false');
|
||||
test(!mouseup, '1) mouseup should be false');
|
||||
test(!click, '1) click should be false');
|
||||
@@ -763,6 +763,10 @@ Test.prototype.tests = {
|
||||
test(greenMouseouts === 1, 'greenMouseouts should be 1');
|
||||
test(groupMouseovers === 1, 'groupMouseovers should be 1');
|
||||
test(groupMouseouts === 1, 'groupMouseouts should be 1');
|
||||
|
||||
//document.body.appendChild(layer.bufferCanvas.element)
|
||||
|
||||
layer.bufferCanvas.element.style.marginTop = '220px';
|
||||
|
||||
},
|
||||
'EVENTS - test event bubbling': function(containerId) {
|
||||
|
Reference in New Issue
Block a user