reworked pixel detection. I now require the dev to use shape.save() to save the pixel data for performance reasons

This commit is contained in:
Eric Rowell 2012-04-01 19:38:30 -07:00
parent 72c0555d0b
commit 6ce9d5489c
6 changed files with 121 additions and 135 deletions

112
dist/kinetic-core.js vendored
View File

@ -1228,11 +1228,11 @@ Kinetic.Stage.prototype = {
* @param {String} typesStr
* @param {function} handler
*/
onContainer: function(typesStr, handler) {
onContent: function(typesStr, handler) {
var types = typesStr.split(' ');
for(var n = 0; n < types.length; n++) {
var baseEvent = types[n];
this.container.addEventListener(baseEvent, handler, false);
this.content.addEventListener(baseEvent, handler, false);
}
},
/**
@ -1278,6 +1278,12 @@ Kinetic.Stage.prototype = {
getContainer: function() {
return this.container;
},
/**
* get content DOM element
*/
getContent: function() {
return this.content;
},
/**
* get stage
*/
@ -1466,8 +1472,7 @@ Kinetic.Stage.prototype = {
this._setMousePosition(evt);
this._setTouchPosition(evt);
this._clearDefaultLayers();
this.pathLayer.clear();
/*
* loop through layers. If at any point an event
@ -1496,13 +1501,6 @@ Kinetic.Stage.prototype = {
}
},
/**
* clear default layers
*/
_clearDefaultLayers: function() {
this.bufferLayer.clear();
this.pathLayer.clear();
},
/**
* begin listening for events by adding event handlers
* to the container
@ -1511,18 +1509,18 @@ Kinetic.Stage.prototype = {
var that = this;
// desktop events
this.container.addEventListener('mousedown', function(evt) {
this.content.addEventListener('mousedown', function(evt) {
that.mouseDown = true;
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('mousemove', function(evt) {
this.content.addEventListener('mousemove', function(evt) {
that.mouseUp = false;
that.mouseDown = false;
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('mouseup', function(evt) {
this.content.addEventListener('mouseup', function(evt) {
that.mouseUp = true;
that.mouseDown = false;
that._handleStageEvent(evt);
@ -1530,11 +1528,11 @@ Kinetic.Stage.prototype = {
that.clickStart = false;
}, false);
this.container.addEventListener('mouseover', function(evt) {
this.content.addEventListener('mouseover', function(evt) {
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('mouseout', function(evt) {
this.content.addEventListener('mouseout', function(evt) {
// if there's a current target shape, run mouseout handlers
var targetShape = that.targetShape;
if(targetShape) {
@ -1543,18 +1541,18 @@ Kinetic.Stage.prototype = {
that.mousePos = undefined;
}, false);
// mobile events
this.container.addEventListener('touchstart', function(evt) {
this.content.addEventListener('touchstart', function(evt) {
evt.preventDefault();
that.touchStart = true;
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('touchmove', function(evt) {
this.content.addEventListener('touchmove', function(evt) {
evt.preventDefault();
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('touchend', function(evt) {
this.content.addEventListener('touchend', function(evt) {
evt.preventDefault();
that.touchEnd = true;
that._handleStageEvent(evt);
@ -1565,8 +1563,8 @@ Kinetic.Stage.prototype = {
* @param {Event} evt
*/
_setMousePosition: function(evt) {
var mouseX = evt.offsetX || (evt.clientX - this._getContainerPosition().left + window.pageXOffset);
var mouseY = evt.offsetY || (evt.clientY - this._getContainerPosition().top + window.pageYOffset);
var mouseX = evt.offsetX || (evt.clientX - this._getContentPosition().left + window.pageXOffset);
var mouseY = evt.offsetY || (evt.clientY - this._getContentPosition().top + window.pageYOffset);
this.mousePos = {
x: mouseX,
y: mouseY
@ -1581,8 +1579,8 @@ Kinetic.Stage.prototype = {
// one finger
var touch = evt.touches[0];
// Get the information for finger #1
var touchX = touch.clientX - this._getContainerPosition().left + window.pageXOffset;
var touchY = touch.clientY - this._getContainerPosition().top + window.pageYOffset;
var touchX = touch.clientX - this._getContentPosition().left + window.pageXOffset;
var touchY = touch.clientY - this._getContentPosition().top + window.pageYOffset;
this.touchPos = {
x: touchX,
@ -1593,8 +1591,8 @@ Kinetic.Stage.prototype = {
/**
* get container position
*/
_getContainerPosition: function() {
var obj = this.container;
_getContentPosition: function() {
var obj = this.content;
var top = 0;
var left = 0;
while(obj && obj.tagName !== 'BODY') {
@ -1648,7 +1646,7 @@ Kinetic.Stage.prototype = {
_prepareDrag: function() {
var that = this;
this.onContainer('mousemove touchmove', function(evt) {
this.onContent('mousemove touchmove', function(evt) {
var go = Kinetic.GlobalObject;
var node = go.drag.node;
if(node) {
@ -1730,7 +1728,7 @@ Kinetic.Stage.prototype = {
}
}, false);
this.onContainer('mouseup touchend mouseout', function(evt) {
this.onContent('mouseup touchend mouseout', function(evt) {
that._endDrag(evt);
});
},
@ -1747,8 +1745,12 @@ Kinetic.Stage.prototype = {
this.container.appendChild(this.content);
// default layers
this.bufferLayer = new Kinetic.Layer();
this.pathLayer = new Kinetic.Layer();
this.bufferLayer = new Kinetic.Layer({
name: 'bufferLayer'
});
this.pathLayer = new Kinetic.Layer({
name: 'pathLayer'
});
// set parents
this.bufferLayer.parent = this;
@ -1933,6 +1935,7 @@ Kinetic.GlobalObject.extend(Kinetic.Group, Kinetic.Node);
*/
Kinetic.Shape = function(config) {
this.className = 'Shape';
this.data = [];
// defaults
if(config.stroke !== undefined || config.strokeWidth !== undefined) {
@ -2060,6 +2063,23 @@ Kinetic.Shape.prototype = {
setDrawFunc: function(func) {
this.drawFunc = func;
},
/**
* save shape data when using pixel detection.
*/
save: function() {
var stage = this.getStage();
var w = stage.width;
var h = stage.height;
var bufferLayer = stage.bufferLayer;
var bufferLayerContext = bufferLayer.getContext();
bufferLayer.clear();
this._draw(bufferLayer);
var imageData = bufferLayerContext.getImageData(0, 0, w, h);
this.data = imageData.data;
},
/**
* draw shape
* @param {Layer} layer Layer that the shape will be drawn on
@ -2108,40 +2128,10 @@ Kinetic.Shape.prototype = {
return pathLayerContext.isPointInPath(pos.x, pos.y);
}
else {
var ax = this.getAbsolutePosition().x;
var ay = this.getAbsolutePosition().y;
var aw = this.getWidth();
var ah = this.getHeight();
/*
* TODO: need to also take into account absolute
* rotation, absolute scale, and center offsets
* to calculate the correct aw, ah, ax, and ay values. Also need
* to implement getHeight and getWidth methods for each Shape
* object
*/
// only check pixels if it's possibly in range
if(pos.x >= ax && pos.x <= (ax + aw) && pos.y >= ay && pos.y <= ay + ah) {
var bufferLayer = stage.bufferLayer;
var bufferLayerContext = bufferLayer.getContext();
this._draw(bufferLayer);
var px = pos.x - ax;
var py = pos.y - ay;
// only get the image data for possible area
var imageData = bufferLayerContext.getImageData(ax, ay, aw, ah);
var data = imageData.data;
var alpha = data[((aw * py) + px) * 4 + 3];
var w = stage.width;
var alpha = this.data[((w * pos.y) + pos.x) * 4 + 3];
return (alpha !== undefined && alpha !== 0);
}
else {
return false;
}
}
}
};
// extend Node

File diff suppressed because one or more lines are too long

View File

@ -17,6 +17,7 @@
*/
Kinetic.Shape = function(config) {
this.className = 'Shape';
this.data = [];
// defaults
if(config.stroke !== undefined || config.strokeWidth !== undefined) {
@ -144,6 +145,23 @@ Kinetic.Shape.prototype = {
setDrawFunc: function(func) {
this.drawFunc = func;
},
/**
* save shape data when using pixel detection.
*/
save: function() {
var stage = this.getStage();
var w = stage.width;
var h = stage.height;
var bufferLayer = stage.bufferLayer;
var bufferLayerContext = bufferLayer.getContext();
bufferLayer.clear();
this._draw(bufferLayer);
var imageData = bufferLayerContext.getImageData(0, 0, w, h);
this.data = imageData.data;
},
/**
* draw shape
* @param {Layer} layer Layer that the shape will be drawn on
@ -192,40 +210,10 @@ Kinetic.Shape.prototype = {
return pathLayerContext.isPointInPath(pos.x, pos.y);
}
else {
var ax = this.getAbsolutePosition().x;
var ay = this.getAbsolutePosition().y;
var aw = this.getWidth();
var ah = this.getHeight();
/*
* TODO: need to also take into account absolute
* rotation, absolute scale, and center offsets
* to calculate the correct aw, ah, ax, and ay values. Also need
* to implement getHeight and getWidth methods for each Shape
* object
*/
// only check pixels if it's possibly in range
if(pos.x >= ax && pos.x <= (ax + aw) && pos.y >= ay && pos.y <= ay + ah) {
var bufferLayer = stage.bufferLayer;
var bufferLayerContext = bufferLayer.getContext();
this._draw(bufferLayer);
var px = pos.x - ax;
var py = pos.y - ay;
// only get the image data for possible area
var imageData = bufferLayerContext.getImageData(ax, ay, aw, ah);
var data = imageData.data;
var alpha = data[((aw * py) + px) * 4 + 3];
var w = stage.width;
var alpha = this.data[((w * pos.y) + pos.x) * 4 + 3];
return (alpha !== undefined && alpha !== 0);
}
else {
return false;
}
}
}
};
// extend Node

View File

@ -198,11 +198,11 @@ Kinetic.Stage.prototype = {
* @param {String} typesStr
* @param {function} handler
*/
onContainer: function(typesStr, handler) {
onContent: function(typesStr, handler) {
var types = typesStr.split(' ');
for(var n = 0; n < types.length; n++) {
var baseEvent = types[n];
this.container.addEventListener(baseEvent, handler, false);
this.content.addEventListener(baseEvent, handler, false);
}
},
/**
@ -248,6 +248,12 @@ Kinetic.Stage.prototype = {
getContainer: function() {
return this.container;
},
/**
* get content DOM element
*/
getContent: function() {
return this.content;
},
/**
* get stage
*/
@ -436,8 +442,7 @@ Kinetic.Stage.prototype = {
this._setMousePosition(evt);
this._setTouchPosition(evt);
this._clearDefaultLayers();
this.pathLayer.clear();
/*
* loop through layers. If at any point an event
@ -466,13 +471,6 @@ Kinetic.Stage.prototype = {
}
},
/**
* clear default layers
*/
_clearDefaultLayers: function() {
this.bufferLayer.clear();
this.pathLayer.clear();
},
/**
* begin listening for events by adding event handlers
* to the container
@ -481,18 +479,18 @@ Kinetic.Stage.prototype = {
var that = this;
// desktop events
this.container.addEventListener('mousedown', function(evt) {
this.content.addEventListener('mousedown', function(evt) {
that.mouseDown = true;
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('mousemove', function(evt) {
this.content.addEventListener('mousemove', function(evt) {
that.mouseUp = false;
that.mouseDown = false;
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('mouseup', function(evt) {
this.content.addEventListener('mouseup', function(evt) {
that.mouseUp = true;
that.mouseDown = false;
that._handleStageEvent(evt);
@ -500,11 +498,11 @@ Kinetic.Stage.prototype = {
that.clickStart = false;
}, false);
this.container.addEventListener('mouseover', function(evt) {
this.content.addEventListener('mouseover', function(evt) {
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('mouseout', function(evt) {
this.content.addEventListener('mouseout', function(evt) {
// if there's a current target shape, run mouseout handlers
var targetShape = that.targetShape;
if(targetShape) {
@ -513,18 +511,18 @@ Kinetic.Stage.prototype = {
that.mousePos = undefined;
}, false);
// mobile events
this.container.addEventListener('touchstart', function(evt) {
this.content.addEventListener('touchstart', function(evt) {
evt.preventDefault();
that.touchStart = true;
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('touchmove', function(evt) {
this.content.addEventListener('touchmove', function(evt) {
evt.preventDefault();
that._handleStageEvent(evt);
}, false);
this.container.addEventListener('touchend', function(evt) {
this.content.addEventListener('touchend', function(evt) {
evt.preventDefault();
that.touchEnd = true;
that._handleStageEvent(evt);
@ -535,8 +533,8 @@ Kinetic.Stage.prototype = {
* @param {Event} evt
*/
_setMousePosition: function(evt) {
var mouseX = evt.offsetX || (evt.clientX - this._getContainerPosition().left + window.pageXOffset);
var mouseY = evt.offsetY || (evt.clientY - this._getContainerPosition().top + window.pageYOffset);
var mouseX = evt.offsetX || (evt.clientX - this._getContentPosition().left + window.pageXOffset);
var mouseY = evt.offsetY || (evt.clientY - this._getContentPosition().top + window.pageYOffset);
this.mousePos = {
x: mouseX,
y: mouseY
@ -551,8 +549,8 @@ Kinetic.Stage.prototype = {
// one finger
var touch = evt.touches[0];
// Get the information for finger #1
var touchX = touch.clientX - this._getContainerPosition().left + window.pageXOffset;
var touchY = touch.clientY - this._getContainerPosition().top + window.pageYOffset;
var touchX = touch.clientX - this._getContentPosition().left + window.pageXOffset;
var touchY = touch.clientY - this._getContentPosition().top + window.pageYOffset;
this.touchPos = {
x: touchX,
@ -563,8 +561,8 @@ Kinetic.Stage.prototype = {
/**
* get container position
*/
_getContainerPosition: function() {
var obj = this.container;
_getContentPosition: function() {
var obj = this.content;
var top = 0;
var left = 0;
while(obj && obj.tagName !== 'BODY') {
@ -618,7 +616,7 @@ Kinetic.Stage.prototype = {
_prepareDrag: function() {
var that = this;
this.onContainer('mousemove touchmove', function(evt) {
this.onContent('mousemove touchmove', function(evt) {
var go = Kinetic.GlobalObject;
var node = go.drag.node;
if(node) {
@ -700,7 +698,7 @@ Kinetic.Stage.prototype = {
}
}, false);
this.onContainer('mouseup touchend mouseout', function(evt) {
this.onContent('mouseup touchend mouseout', function(evt) {
that._endDrag(evt);
});
},
@ -717,8 +715,12 @@ Kinetic.Stage.prototype = {
this.container.appendChild(this.content);
// default layers
this.bufferLayer = new Kinetic.Layer();
this.pathLayer = new Kinetic.Layer();
this.bufferLayer = new Kinetic.Layer({
name: 'bufferLayer'
});
this.pathLayer = new Kinetic.Layer({
name: 'pathLayer'
});
// set parents
this.bufferLayer.parent = this;

View File

@ -548,16 +548,17 @@ Test.prototype.tests = {
log('mouseout');
});
darth.on('dragend', function() {
this.save();
});
layer.add(darth);
stage.add(layer);
//darth.save();
};
imageObj.src = '../lion.png';
},
/*
* TODO: need to implement area x, y, width and height
* in order to support other shape pixel detection
*/
/*
'EVENTS - star pixel detection': function(containerId) {
var imageObj = new Image();
imageObj.onload = function() {
@ -591,12 +592,17 @@ Test.prototype.tests = {
log('mouseout');
});
star.on('dragend', function() {
this.save();
});
layer.add(star);
stage.add(layer);
star.save();
};
imageObj.src = '../lion.png';
},
*/
'EVENTS - drag events click': function(containerId) {
var stage = new Kinetic.Stage({
container: containerId,