Reputation: 61
I'm trying to animate the movement of image across the canvas using requestAnimationFrame
in 2 directions using a recursive function.
Animate 1
move the image in one direction on 1 click and then the opposite direction on 2nd click. Animate 2
moves the image in one direction.
Before I get to test my recursive function, my requestAnimationFrame
returns an error on my first click of Animate 1
. I ran a simple debug to find out that after my first click on Animate 1
, the image animates successfully to the left. But as it exits the animation2()
, it returns back to requestAnimationFrame
to return the following error:
Uncaught TypeError: Failed to execute 'requestAnimationFrame' on 'Window': The callback provided as parameter 1 is not a function.
What causes this error? And I'm pretty sure my recursive function will not work as it is. What correction should I make?
The following is my crude coding.
var canvas = document.getElementsByTagName("canvas")[0];
canvas.width = 286;
canvas.height = 60;
var ctx = canvas.getContext("2d");
trackTransforms(ctx);
var img = new Image();
img.src = "https://www.dropbox.com/s/bq8wk2rashbsjxw/Capture.PNG?raw=1";
window.onload = function() {
redraw();
};
var button1 = false;
var pause;
var coordinate = new Array();
coordinate[0] = {
X1: 286,
X2: 136
};
coordinate[1] = {
X1: 150,
X2: 0
};
var coordinate2 = new Array();
coordinate2[0] = {
X1: 286,
X2: 136
};
coordinate2[1] = {
X1: 150,
X2: 0
};
function animation() {
var track = coordinate.slice(); // copy the array to keep track of which items are left to process after click event
coordinate.forEach(function(item, index) {
track.splice(track.indexOf(item), 1); // remove the item from the processed array
button1 = true;
animation2(item);
button1 = false;
button.onclick = function(event) {
animation(track); // call function in the callback passing in the unprocessed items array
event.target.onclick = null; // remove the click event so it can't be fired again
}
});
}
var fps = 1; // animation speed
var slideX = 0;
function animation2(coordinate) {
if (button1) {
var cornerRight = coordinate.X1; // animation in to and fro
var cornerLeft = coordinate.X2;
} else {
var cornerRight = coordinate2[0].X1; // animation in single direction
var cornerLeft = coordinate2[0].X2; // change index number to change direction
}
var cornerCenterX = (cornerLeft + cornerRight) / 2;
var canvasCenterX = canvas.width / 2;
if (cornerCenterX > canvasCenterX) {
// to determine image to move right or left
slideX -= fps;
var distanceX = Math.abs(cornerCenterX - canvasCenterX);
var pt = ctx.transformedPoint(slideX, 0);
ctx.translate(pt.x, pt.y);
redraw();
if (button1) {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(animation2(coordinate));
} else {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(animation2);
}
} else if (cornerCenterX < canvasCenterX) {
slideX += fps;
var distanceX = Math.abs(cornerCenterX - canvasCenterX);
var pt = ctx.transformedPoint(slideX, 0);
ctx.translate(pt.x, pt.y);
redraw();
if (button1) {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(animation2(coordinate));
} else {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(animation2);
}
}
}
function redraw() {
var p1 = ctx.transformedPoint(0, 0);
var p2 = ctx.transformedPoint(canvas.width, canvas.height);
ctx.clearRect(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.drawImage(img, 0, 0);
}
function reset() {
var p1 = ctx.transformedPoint(0, 0);
var p2 = ctx.transformedPoint(canvas.width, canvas.height);
ctx.clearRect(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
slideX = 0;
button1 = false;
}
function trackTransforms(ctx) {
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var xform = svg.createSVGMatrix();
ctx.getTransform = function() {
return xform;
};
var savedTransforms = [];
var save = ctx.save;
ctx.save = function() {
savedTransforms.push(xform.translate(0, 0));
return save.call(ctx);
};
var restore = ctx.restore;
ctx.restore = function() {
xform = savedTransforms.pop();
return restore.call(ctx);
};
var translate = ctx.translate;
ctx.translate = function(dx, dy) {
xform = xform.translate(dx, dy);
return translate.call(ctx, dx, dy);
};
var transform = ctx.transform;
ctx.transform = function(a, b, c, d, e, f) {
var m2 = svg.createSVGMatrix();
m2.a = a;
m2.b = b;
m2.c = c;
m2.d = d;
m2.e = e;
m2.f = f;
xform = xform.multiply(m2);
return transform.call(ctx, a, b, c, d, e, f);
};
var setTransform = ctx.setTransform;
ctx.setTransform = function(a, b, c, d, e, f) {
xform.a = a;
xform.b = b;
xform.c = c;
xform.d = d;
xform.e = e;
xform.f = f;
return setTransform.call(ctx, a, b, c, d, e, f);
};
// convert the mouse coordinates (in pixels) into the global space of your SVG document
var pt = svg.createSVGPoint();
ctx.transformedPoint = function(x, y) {
pt.x = x;
pt.y = y;
return pt.matrixTransform(xform.inverse());
};
}
body {
background: #eee;
margin: 1em;
text-align: center;
}
canvas {
display: block;
margin: 1em auto;
background: #fff;
border: 1px solid #ccc;
}
<input id="button" type="button" value="Animate 1" onclick="animation();" />
<input id="button2" type="button" value="Animate 2" onclick="animation2();" />
<input id="button3" type="button" value="Reset" onclick="reset();" />
<canvas id="main"></canvas>
Upvotes: 1
Views: 1042
Reputation: 17584
Following up from the comments:
You should read more about the requestAnimationFrame method:
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
The syntax is: window.requestAnimationFrame(callback);
That callback
is a parameter specifying a function to call when it's time to update your animation for the next repaint.
Using your code as an example:
animation2
is a function animation2(coordinate)
is NOT a functionfunction() { animation2(coordinate) }
is a functionConsider reading about nameless/anonymous functions
Here is your code working without errors:
var canvas = document.getElementsByTagName("canvas")[0];
canvas.width = 286;
canvas.height = 60;
var ctx = canvas.getContext("2d");
trackTransforms(ctx);
var img = new Image();
img.src = "https://www.dropbox.com/s/bq8wk2rashbsjxw/Capture.PNG?raw=1";
window.onload = function() {
redraw();
};
var button1 = false;
var pause;
var coordinate = new Array();
coordinate[0] = {
X1: 286,
X2: 136
};
coordinate[1] = {
X1: 150,
X2: 0
};
var coordinate2 = new Array();
coordinate2[0] = {
X1: 286,
X2: 136
};
coordinate2[1] = {
X1: 150,
X2: 0
};
function animation() {
var track = coordinate.slice(); // copy the array to keep track of which items are left to process after click event
coordinate.forEach(function(item, index) {
track.splice(track.indexOf(item), 1); // remove the item from the processed array
button1 = true;
animation2(item);
button1 = false;
button.onclick = function(event) {
animation(track); // call function in the callback passing in the unprocessed items array
event.target.onclick = null; // remove the click event so it can't be fired again
}
});
}
var fps = 1; // animation speed
var slideX = 0;
function animation2(coordinate) {
if (button1) {
var cornerRight = coordinate.X1; // animation in to and fro
var cornerLeft = coordinate.X2;
} else {
var cornerRight = coordinate2[0].X1; // animation in single direction
var cornerLeft = coordinate2[0].X2; // change index number to change direction
}
var cornerCenterX = (cornerLeft + cornerRight) / 2;
var canvasCenterX = canvas.width / 2;
if (cornerCenterX > canvasCenterX) {
// to determine image to move right or left
slideX -= fps;
var distanceX = Math.abs(cornerCenterX - canvasCenterX);
var pt = ctx.transformedPoint(slideX, 0);
ctx.translate(pt.x, pt.y);
redraw();
if (button1) {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(function() { animation2(coordinate) });
} else {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(animation2);
}
} else if (cornerCenterX < canvasCenterX) {
slideX += fps;
var distanceX = Math.abs(cornerCenterX - canvasCenterX);
var pt = ctx.transformedPoint(slideX, 0);
ctx.translate(pt.x, pt.y);
redraw();
if (button1) {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(function() { animation2(coordinate) });
} else {
if (Math.abs(slideX) < distanceX) requestAnimationFrame(animation2);
}
}
}
function redraw() {
var p1 = ctx.transformedPoint(0, 0);
var p2 = ctx.transformedPoint(canvas.width, canvas.height);
ctx.clearRect(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.drawImage(img, 0, 0);
}
function reset() {
var p1 = ctx.transformedPoint(0, 0);
var p2 = ctx.transformedPoint(canvas.width, canvas.height);
ctx.clearRect(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
slideX = 0;
button1 = false;
}
function trackTransforms(ctx) {
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var xform = svg.createSVGMatrix();
ctx.getTransform = function() {
return xform;
};
var savedTransforms = [];
var save = ctx.save;
ctx.save = function() {
savedTransforms.push(xform.translate(0, 0));
return save.call(ctx);
};
var restore = ctx.restore;
ctx.restore = function() {
xform = savedTransforms.pop();
return restore.call(ctx);
};
var translate = ctx.translate;
ctx.translate = function(dx, dy) {
xform = xform.translate(dx, dy);
return translate.call(ctx, dx, dy);
};
var transform = ctx.transform;
ctx.transform = function(a, b, c, d, e, f) {
var m2 = svg.createSVGMatrix();
m2.a = a;
m2.b = b;
m2.c = c;
m2.d = d;
m2.e = e;
m2.f = f;
xform = xform.multiply(m2);
return transform.call(ctx, a, b, c, d, e, f);
};
var setTransform = ctx.setTransform;
ctx.setTransform = function(a, b, c, d, e, f) {
xform.a = a;
xform.b = b;
xform.c = c;
xform.d = d;
xform.e = e;
xform.f = f;
return setTransform.call(ctx, a, b, c, d, e, f);
};
// convert the mouse coordinates (in pixels) into the global space of your SVG document
var pt = svg.createSVGPoint();
ctx.transformedPoint = function(x, y) {
pt.x = x;
pt.y = y;
return pt.matrixTransform(xform.inverse());
};
}
body {
background: #eee;
margin: 1em;
text-align: center;
}
canvas {
display: block;
margin: 1em auto;
background: #fff;
border: 1px solid #ccc;
}
<input id="button" type="button" value="Animate 1" onclick="animation();" />
<input id="button2" type="button" value="Animate 2" onclick="animation2();" />
<input id="button3" type="button" value="Reset" onclick="reset();" />
<canvas id="main"></canvas>
Upvotes: 1