finished pixel detection algo which can be applied to any Shape. This enables a lot of new functionality, such as image pixel detection, shape border detection, and custom shape detection that isn't drawn with a standard path

This commit is contained in:
Eric Rowell 2012-04-01 01:08:33 -07:00
parent 08e2b74da9
commit 95fabe9160
6 changed files with 140 additions and 17 deletions

43
dist/kinetic-core.js vendored
View File

@ -1280,7 +1280,7 @@ Kinetic.Stage.prototype = {
this.targetFound = true; this.targetFound = true;
} }
if(shape.visible && pos !== undefined && shape._isPointInPath(pos)) { if(shape.visible && pos !== undefined && shape._isPointInShape(pos)) {
// handle onmousedown // handle onmousedown
if(!isDragging && this.mouseDown) { if(!isDragging && this.mouseDown) {
this.mouseDown = false; this.mouseDown = false;
@ -1482,8 +1482,8 @@ Kinetic.Stage.prototype = {
* clear default layers * clear default layers
*/ */
_clearDefaultLayers: function() { _clearDefaultLayers: function() {
var pathLayer = this.pathLayer; this.bufferLayer.clear();
pathLayer.clear(); this.pathLayer.clear();
}, },
/** /**
* begin listening for events by adding event handlers * begin listening for events by adding event handlers
@ -1902,6 +1902,8 @@ Kinetic.GlobalObject.extend(Kinetic.Group, Kinetic.Node);
* @config {Number} [strokeWidth] stroke width * @config {Number} [strokeWidth] stroke width
* @config {String} [lineJoin] line join. Can be "miter", "round", or "bevel". The default * @config {String} [lineJoin] line join. Can be "miter", "round", or "bevel". The default
* is "miter" * is "miter"
* @config {String} [detectionType] shape detection type. Can be "path" or "pixel".
* The default is "path" because it performs better
*/ */
Kinetic.Shape = function(config) { Kinetic.Shape = function(config) {
this.className = 'Shape'; this.className = 'Shape';
@ -1916,6 +1918,10 @@ Kinetic.Shape = function(config) {
} }
} }
if(config.detectionType === undefined) {
config.detectionType = 'path';
}
// required // required
this.drawFunc = config.drawFunc; this.drawFunc = config.drawFunc;
@ -2066,12 +2072,33 @@ Kinetic.Shape.prototype = {
* custom isPointInPath method which can use path detection * custom isPointInPath method which can use path detection
* or pixel detection * or pixel detection
*/ */
_isPointInPath: function(pos) { _isPointInShape: function(pos) {
var stage = this.getStage(); var stage = this.getStage();
var pathLayer = stage.pathLayer;
var pathLayerContext = pathLayer.getContext(); if(this.detectionType === 'path') {
this._draw(pathLayer); var pathLayer = stage.pathLayer;
return pathLayerContext.isPointInPath(pos.x, pos.y); var pathLayerContext = pathLayer.getContext();
this._draw(pathLayer);
return pathLayerContext.isPointInPath(pos.x, pos.y);
}
else {
var bufferLayer = stage.bufferLayer;
var bufferLayerContext = bufferLayer.getContext();
this._draw(bufferLayer);
var w = stage.width;
var h = stage.height;
var x = pos.x;
var y = pos.y;
var imageData = bufferLayerContext.getImageData(0, 0, w, h);
var data = imageData.data;
var alpha = data[((w * y) + x) * 4 + 3];
return (alpha !== undefined && alpha !== 0);
}
} }
}; };
// extend Node // extend Node

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,8 @@
* @config {Number} [strokeWidth] stroke width * @config {Number} [strokeWidth] stroke width
* @config {String} [lineJoin] line join. Can be "miter", "round", or "bevel". The default * @config {String} [lineJoin] line join. Can be "miter", "round", or "bevel". The default
* is "miter" * is "miter"
* @config {String} [detectionType] shape detection type. Can be "path" or "pixel".
* The default is "path" because it performs better
*/ */
Kinetic.Shape = function(config) { Kinetic.Shape = function(config) {
this.className = 'Shape'; this.className = 'Shape';
@ -26,6 +28,10 @@ Kinetic.Shape = function(config) {
} }
} }
if(config.detectionType === undefined) {
config.detectionType = 'path';
}
// required // required
this.drawFunc = config.drawFunc; this.drawFunc = config.drawFunc;
@ -176,12 +182,33 @@ Kinetic.Shape.prototype = {
* custom isPointInPath method which can use path detection * custom isPointInPath method which can use path detection
* or pixel detection * or pixel detection
*/ */
_isPointInPath: function(pos) { _isPointInShape: function(pos) {
var stage = this.getStage(); var stage = this.getStage();
var pathLayer = stage.pathLayer;
var pathLayerContext = pathLayer.getContext(); if(this.detectionType === 'path') {
this._draw(pathLayer); var pathLayer = stage.pathLayer;
return pathLayerContext.isPointInPath(pos.x, pos.y); var pathLayerContext = pathLayer.getContext();
this._draw(pathLayer);
return pathLayerContext.isPointInPath(pos.x, pos.y);
}
else {
var bufferLayer = stage.bufferLayer;
var bufferLayerContext = bufferLayer.getContext();
this._draw(bufferLayer);
var w = stage.width;
var h = stage.height;
var x = pos.x;
var y = pos.y;
var imageData = bufferLayerContext.getImageData(0, 0, w, h);
var data = imageData.data;
var alpha = data[((w * y) + x) * 4 + 3];
return (alpha !== undefined && alpha !== 0);
}
} }
}; };
// extend Node // extend Node

View File

@ -254,7 +254,7 @@ Kinetic.Stage.prototype = {
this.targetFound = true; this.targetFound = true;
} }
if(shape.visible && pos !== undefined && shape._isPointInPath(pos)) { if(shape.visible && pos !== undefined && shape._isPointInShape(pos)) {
// handle onmousedown // handle onmousedown
if(!isDragging && this.mouseDown) { if(!isDragging && this.mouseDown) {
this.mouseDown = false; this.mouseDown = false;
@ -456,8 +456,8 @@ Kinetic.Stage.prototype = {
* clear default layers * clear default layers
*/ */
_clearDefaultLayers: function() { _clearDefaultLayers: function() {
var pathLayer = this.pathLayer; this.bufferLayer.clear();
pathLayer.clear(); this.pathLayer.clear();
}, },
/** /**
* begin listening for events by adding event handlers * begin listening for events by adding event handlers

View File

@ -519,6 +519,75 @@ Test.prototype.tests = {
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../darth-vader.jpg';
}, },
/*
* WARNING: this functional test will only pass if it's hosted on
* a webserver due to cross domain security issues
*/
'EVENTS - image pixel detection': function(containerId) {
var imageObj = new Image();
imageObj.onload = function() {
var stage = new Kinetic.Stage({
container: containerId,
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var darth = new Kinetic.Image({
x: 200,
y: 40,
image: imageObj,
detectionType: 'pixel',
draggable: true
});
darth.on('mouseover', function() {
log('mouseover');
});
darth.on('mouseout', function() {
log('mouseout');
});
layer.add(darth);
stage.add(layer);
};
imageObj.src = '../lion.png';
},
'EVENTS - star pixel detection': function(containerId) {
var imageObj = new Image();
imageObj.onload = function() {
var stage = new Kinetic.Stage({
container: containerId,
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var star = new Kinetic.Star({
x: 200,
y: 100,
points: 10,
innerRadius: 40,
outerRadius: 70,
fill: 'green',
stroke: 'blue',
strokeWidth: 20,
detectionType: 'pixel',
draggable: true
});
star.on('mouseover', function() {
log('mouseover');
});
star.on('mouseout', function() {
log('mouseout');
});
layer.add(star);
stage.add(layer);
};
imageObj.src = '../lion.png';
},
'EVENTS - drag events click': function(containerId) { 'EVENTS - drag events click': function(containerId) {
var stage = new Kinetic.Stage({ var stage = new Kinetic.Stage({
container: containerId, container: containerId,

BIN
tests/lion.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB