fixed animation race condition bug that sometimes produced multiple requestAnimFrame calls, and also changed throttle property to be in fps (it used to be in ms). This will make it more consistent with other properties related to frame rates

This commit is contained in:
Eric Rowell 2012-05-03 12:05:54 -07:00
parent 3585e000b6
commit 7d92a2099e
6 changed files with 44 additions and 34 deletions

29
dist/kinetic-core.js vendored
View File

@ -3,7 +3,7 @@
* http://www.kineticjs.com/ * http://www.kineticjs.com/
* Copyright 2012, Eric Rowell * Copyright 2012, Eric Rowell
* Licensed under the MIT or GPL Version 2 licenses. * Licensed under the MIT or GPL Version 2 licenses.
* Date: May 02 2012 * Date: May 03 2012
* *
* Copyright (C) 2011 - 2012 by Eric Rowell * Copyright (C) 2011 - 2012 by Eric Rowell
* *
@ -44,6 +44,7 @@ Kinetic.GlobalObject = {
tempNodes: [], tempNodes: [],
animations: [], animations: [],
animIdCounter: 0, animIdCounter: 0,
animRunning: false,
dragTimeInterval: 0, dragTimeInterval: 0,
maxDragTimeInterval: 20, maxDragTimeInterval: 20,
frame: { frame: {
@ -132,12 +133,14 @@ Kinetic.GlobalObject = {
}); });
} }
else { else {
this.animRunning = false;
this.frame.lastTime = 0; this.frame.lastTime = 0;
} }
}, },
_handleAnimation: function() { _handleAnimation: function() {
var that = this; var that = this;
if(this.animations.length > 0) { if(!this.animRunning) {
this.animRunning = true;
that._animationLoop(); that._animationLoop();
} }
else { else {
@ -2177,7 +2180,7 @@ Kinetic.GlobalObject.extend(Kinetic.Stage, Kinetic.Node);
*/ */
Kinetic.Layer = function(config) { Kinetic.Layer = function(config) {
this.setDefaultAttrs({ this.setDefaultAttrs({
throttle: 12 throttle: 80
}); });
this.nodeType = 'Layer'; this.nodeType = 'Layer';
@ -2206,10 +2209,11 @@ Kinetic.Layer.prototype = {
var date = new Date(); var date = new Date();
var time = date.getTime(); var time = date.getTime();
var timeDiff = time - this.lastDrawTime; var timeDiff = time - this.lastDrawTime;
var tt = 1000 / throttle;
if(timeDiff >= throttle) { if(timeDiff >= tt) {
this._draw(); this._draw();
this.lastDrawTime = time;
if(this.drawTimeout !== undefined) { if(this.drawTimeout !== undefined) {
clearTimeout(this.drawTimeout); clearTimeout(this.drawTimeout);
this.drawTimeout = undefined; this.drawTimeout = undefined;
@ -2221,15 +2225,12 @@ Kinetic.Layer.prototype = {
*/ */
else if(this.drawTimeout === undefined) { else if(this.drawTimeout === undefined) {
var that = this; var that = this;
/* /*
* if timeout duration is too short, we will * wait 17ms before trying again (60fps)
* get a lot of unecessary layer draws. Make sure */
* that the timeout is slightly more than the throttle
* amount
*/
this.drawTimeout = setTimeout(function() { this.drawTimeout = setTimeout(function() {
that.draw(); that.draw();
}, throttle + 10); }, 17);
} }
}, },
/** /**
@ -2299,6 +2300,10 @@ Kinetic.Layer.prototype = {
* private draw children * private draw children
*/ */
_draw: function() { _draw: function() {
var date = new Date();
var time = date.getTime();
this.lastDrawTime = time;
// before draw handler // before draw handler
if(this.beforeDrawFunc !== undefined) { if(this.beforeDrawFunc !== undefined) {
this.beforeDrawFunc(); this.beforeDrawFunc();

File diff suppressed because one or more lines are too long

View File

@ -16,6 +16,7 @@ Kinetic.GlobalObject = {
tempNodes: [], tempNodes: [],
animations: [], animations: [],
animIdCounter: 0, animIdCounter: 0,
animRunning: false,
dragTimeInterval: 0, dragTimeInterval: 0,
maxDragTimeInterval: 20, maxDragTimeInterval: 20,
frame: { frame: {
@ -104,12 +105,14 @@ Kinetic.GlobalObject = {
}); });
} }
else { else {
this.animRunning = false;
this.frame.lastTime = 0; this.frame.lastTime = 0;
} }
}, },
_handleAnimation: function() { _handleAnimation: function() {
var that = this; var that = this;
if(this.animations.length > 0) { if(!this.animRunning) {
this.animRunning = true;
that._animationLoop(); that._animationLoop();
} }
else { else {

View File

@ -11,7 +11,7 @@
*/ */
Kinetic.Layer = function(config) { Kinetic.Layer = function(config) {
this.setDefaultAttrs({ this.setDefaultAttrs({
throttle: 12 throttle: 80
}); });
this.nodeType = 'Layer'; this.nodeType = 'Layer';
@ -40,10 +40,11 @@ Kinetic.Layer.prototype = {
var date = new Date(); var date = new Date();
var time = date.getTime(); var time = date.getTime();
var timeDiff = time - this.lastDrawTime; var timeDiff = time - this.lastDrawTime;
var tt = 1000 / throttle;
if(timeDiff >= throttle) { if(timeDiff >= tt) {
this._draw(); this._draw();
this.lastDrawTime = time;
if(this.drawTimeout !== undefined) { if(this.drawTimeout !== undefined) {
clearTimeout(this.drawTimeout); clearTimeout(this.drawTimeout);
this.drawTimeout = undefined; this.drawTimeout = undefined;
@ -55,15 +56,12 @@ Kinetic.Layer.prototype = {
*/ */
else if(this.drawTimeout === undefined) { else if(this.drawTimeout === undefined) {
var that = this; var that = this;
/* /*
* if timeout duration is too short, we will * wait 17ms before trying again (60fps)
* get a lot of unecessary layer draws. Make sure */
* that the timeout is slightly more than the throttle
* amount
*/
this.drawTimeout = setTimeout(function() { this.drawTimeout = setTimeout(function() {
that.draw(); that.draw();
}, throttle + 10); }, 17);
} }
}, },
/** /**
@ -133,6 +131,10 @@ Kinetic.Layer.prototype = {
* private draw children * private draw children
*/ */
_draw: function() { _draw: function() {
var date = new Date();
var time = date.getTime();
this.lastDrawTime = time;
// before draw handler // before draw handler
if(this.beforeDrawFunc !== undefined) { if(this.beforeDrawFunc !== undefined) {
this.beforeDrawFunc(); this.beforeDrawFunc();

View File

@ -10,7 +10,7 @@ function log(message) {
* Test constructor * Test constructor
*/ */
function Test() { function Test() {
this.testOnly = 'SHAPES - add sprite'; this.testOnly = '';
this.counter = 0; this.counter = 0;
} }
/** /**

View File

@ -88,7 +88,7 @@ Test.prototype.tests = {
group.add(circle); group.add(circle);
layer.draw(); layer.draw();
var expectedJson = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":12,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"radius":70,"fill":"green","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"name":"myCircle","alpha":1,"x":289,"y":100,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":true},"nodeType":"Shape","shapeType":"Circle"}]}]}]}'; var expectedJson = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"radius":70,"fill":"green","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"name":"myCircle","alpha":1,"x":289,"y":100,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":true},"nodeType":"Shape","shapeType":"Circle"}]}]}]}';
test(stage.toJSON() === expectedJson, 'problem with serialization'); test(stage.toJSON() === expectedJson, 'problem with serialization');
}, },
'STAGE - reset stage': function(containerId) { 'STAGE - reset stage': function(containerId) {
@ -173,7 +173,7 @@ Test.prototype.tests = {
height: 200 height: 200
}); });
var json = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":12,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"radius":70,"fill":"green","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"name":"myCircle","alpha":1,"x":289,"y":100,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":true},"nodeType":"Shape","shapeType":"Circle"}]}]}]}'; var json = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"radius":70,"fill":"green","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"name":"myCircle","alpha":1,"x":289,"y":100,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":true},"nodeType":"Shape","shapeType":"Circle"}]}]}]}';
stage.load(json); stage.load(json);
test(stage.toJSON() === json, "serialized stage is incorrect"); test(stage.toJSON() === json, "serialized stage is incorrect");
@ -209,7 +209,7 @@ Test.prototype.tests = {
group.add(triangle); group.add(triangle);
layer.draw(); layer.draw();
var expectedJson = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":12,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"fill":"#00D2FF","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"myTriangle"},"nodeType":"Shape"}]}]}]}'; var expectedJson = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"fill":"#00D2FF","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"myTriangle"},"nodeType":"Shape"}]}]}]}';
test(stage.toJSON() === expectedJson, "problem with serialization"); test(stage.toJSON() === expectedJson, "problem with serialization");
}, },
'STAGE - load stage with custom shape using json': function(containerId) { 'STAGE - load stage with custom shape using json': function(containerId) {
@ -228,7 +228,7 @@ Test.prototype.tests = {
context.closePath(); context.closePath();
this.fillStroke(); this.fillStroke();
}; };
var json = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":12,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"fill":"#00D2FF","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"myTriangle"},"nodeType":"Shape"}]}]}]}'; var json = '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Group","children":[{"attrs":{"fill":"#00D2FF","stroke":"black","strokeWidth":4,"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"myTriangle"},"nodeType":"Shape"}]}]}]}';
stage.load(json); stage.load(json);
var customShape = stage.get('#myTriangle')[0]; var customShape = stage.get('#myTriangle')[0];
@ -1030,7 +1030,7 @@ Test.prototype.tests = {
var json = stage.toJSON(); var json = stage.toJSON();
test(json === '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":12,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"crop":{"x":0,"y":0},"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":200,"y":60,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":50,"y":150},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"darth"},"nodeType":"Shape","shapeType":"Image"}]}]}'); test(json === '{"attrs":{"width":578,"height":200,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"crop":{"x":0,"y":0},"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":200,"y":60,"scale":{"x":1,"y":1},"rotation":0,"centerOffset":{"x":50,"y":150},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"darth"},"nodeType":"Shape","shapeType":"Image"}]}]}');
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../darth-vader.jpg';
}, },
@ -2780,7 +2780,6 @@ Test.prototype.tests = {
var amplitude = 150; var amplitude = 150;
var period = 1000; var period = 1000;
// in ms
var centerX = 0; var centerX = 0;
stage.onFrame(function(frame) { stage.onFrame(function(frame) {
@ -2796,6 +2795,7 @@ Test.prototype.tests = {
test(go.animations.length === 0, 'should be no animations running'); test(go.animations.length === 0, 'should be no animations running');
test(stage.animRunning === false, 'animRunning should be false'); test(stage.animRunning === false, 'animRunning should be false');
rect.transitionTo({ rect.transitionTo({
x: 300, x: 300,
duration: 1, duration: 1,
@ -2810,6 +2810,6 @@ Test.prototype.tests = {
test(go.animations.length === 1, 'should be no animations running'); test(go.animations.length === 1, 'should be no animations running');
test(stage.animRunning === true, 'animRunning should be false'); test(stage.animRunning === true, 'animRunning should be false');
} }
}); });
} }
}; };