How can I make an animation effect on the canvas while moving? - javascript

Is it possible to make an animation effect on the canvas while moving?
I just need to make an animation movement between canvas' positions,
Like in css3: -webkit-transition-duration: 1s;
Any help is appreciated.
<html>
<head>
<style>
#myCanvas {
-webkit-transition-duration: 1s;
}
</style>
<title>JS Bin</title>
</head>
<body>
<canvas id="myCanvas" width="1280" height="600" style="border:1px solid #d3d3d3;color:red;"></canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var w = document.getElementById("myCanvas");
timer = setInterval(function() {
var f = Math.floor(1+Math.random()*680);
var f2 = Math.floor(1+Math.random()*400);
console.log (f, f2);
ctx.fillStyle="#FF0000";
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillRect(f, f2, 100, 50);
w.onclick = function() {
clearInterval(timer);
falling();
}
}, 300 //the seconds of interval movement)
function falling(){
ctx.clearRect(0,0,c.width,c.height);
ctx.fillRect(500,500,100,50)
}
</script>
</body>
</html>

Sure. If you just want to calculate interim positions along a line from a starting point to an ending point then you can do it like this:
// percentComplete is a number between 0.00 and 1.00
// representing the current progress of the animation from start to end
var x = startingX+(endingX-startingX)*percentComplete;
var y = startingY+(endingY-startingY)*percentComplete;
If you want to animate with flair, then you can use Robert Penner's easing functions to animate in a non-linear way.
To include a fixed duration for your animation you can calculate percentComplete based as:
var percentComplete = elapsedTime / animationDuration;

Related

How to animate fill opacity of a context in HTML5 canvas?

How can I animate fill opacity of a context (or add a fade-in effect) in HTML canvas?
For example at following example the ctx.fillStyle fill opacity is set to 0 and how can I animate it to 1?
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.fillStyle = 'rgba(255, 165, 0, 0)';
ctx.rect(20, 20, 150, 100);
ctx.fill();
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
You can't "animate" like you would with CSS. With a canvas, you're drawing the primative, so you'll have to do the math and timing yourself.
Here is a simple linear progression from one value to another.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
const duration = 1000; // ms
const step = 10; // ms
let opacity = 0;
function draw() {
if (opacity == 1) return;
opacity += (step / duration);
ctx.clearRect(20, 20, 150, 100);
ctx.beginPath();
ctx.fillStyle = `rgba(255, 165, 0, ${opacity})`;
ctx.rect(20, 20, 150, 100);
ctx.fill();
setTimeout(draw, step);
}
draw();
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
Basically, you keep track of the current opacity, how long you want it to go, and how frequently you want it to trigger. Then, you increase your opacity by the percent of your step to your duration and redraw.
Also, since you are dealing with opacity, you have to remember to clear it each step as well, or it'll get dark really fast.
You could also use window.requestAnimationFrame, but then (if you want to control the speed), you'll need to track time instead of step:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
const duration = 1000; // ms
let lastTime = performance.now();
let opacity = 0;
function draw(now) {
if (opacity >= 1) return;
opacity += ((now - lastTime) / duration);
lastTime = now;
ctx.clearRect(20, 20, 150, 100);
ctx.beginPath();
ctx.fillStyle = `rgba(255, 165, 0, ${opacity})`;
ctx.rect(20, 20, 150, 100);
ctx.fill();
window.requestAnimationFrame(draw);
}
draw(lastTime);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
Notice now instead of opacity += step / duration, we're using the number of milliseconds since our last update opacity += (now - lastTime) / duration.
If you want to do different transitions (like step-in-out), you would need to tweak the amount of opacity increase as a factor of time.
You can achieve this using window.requestAnimationFrame:
var
/* Save the canvas' context. */
ctx = document.getElementById("myCanvas").getContext("2d"),
/* The starting opacity. */
opacity = 0,
/* The duration of the animation in milliseconds. */
duration = 500,
/* Cache the starting time in milliseconds since page load. */
past = performance.now();
/* The animation function. */
function animate(present) {
/* Find the difference between the previous and current times. */
var step = present - past;
/* Set the present time to past. */
past = present;
/* Increment the opacity by a linear step. */
opacity += step / duration;
/* Create the shape. */
ctx.beginPath();
ctx.fillStyle = "rgba(255, 165, 0, " + opacity + ")";
ctx.clearRect(20, 20, 150, 100);
ctx.rect(20, 20, 150, 100);
ctx.fill();
/* Continue the animation until the opacity is 1. */
if (opacity < 1) window.requestAnimationFrame(animate);
}
/* Start the animation. */
window.requestAnimationFrame(animate);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
Notes:
You can adjust the speed of the animation by changing the duration to what suits you best. The value is in milliseconds.
On each call of animate, we use clearRect to clear the canvas, to avoid creating one shape on top of another, so that the opacity is incremented as expected.
Different browsers handle requestAnimationFrame differently, so to achieve a consistent, cross-browser result you must use a polyfill that accounts for the differences between browsers. I have provided one below.
Another way to proceed with the animation would be through the use of setInterval, but I believe this is a thing of the past. See this article for more.
Polyfill:
(This polyfill is a modified version of this one, created by Paul Irish)
;(function (prefices, lastTime) {
/* Iterate over every browser-engine-specific prefix. */
for (var i = 0; i < prefices.length && !window.requestAnimationFrame; i++) {
/* Normalise requestAnimationFrame and cancelAnimationFrame. */
window.requestAnimationFrame = window[prefices[i] + "RequestAnimationFrame"];
window.cancelAnimationFrame =
window[prefices[i] + "CancelAnimationFrame"] ||
window[prefices[i] + "CancelRequestAnimationFrame"];
}
/* If requestAnimationFrame is not defined use a custom function. */
window.requestAnimationFrame = window.requestAnimationFrame
|| function (callback, element) {
var
/* Save the present time and the time between it and the last time. */
now = Date.now() || new Date().getTime(),
timeToCall = Math.max(0, 16 - (now - lastTime)),
/* Save the id of the timeout. */
id = window.setTimeout(function () {
/* Call the callback function passing the time passed & the element. */
callback(now + timeToCall, element);
}, timeToCall);
/* Update the last time with the present time plus the time in between. */
lastTime = now + timeToCall;
/* Return the id of the timeout. */
return id;
};
/* If cancelAnimationFrame is not defined set it to clear the timeout. */
window.cancelAnimationFrame = window.cancelAnimationFrame || function (id) {
clearTimeout(id);
}
})(["webkit", "moz", "ms", "o"], 0);

Gradually fade to colour using JS

I am trying to make a rectangle gradually change its colour (fade) from yellow to white using Javascript after a button is pressed. Sadly my code does not work. Could you help me figure out what is wrong with the code and how to fix it?
I have just begun studying Javascript. Sorry, if this question is stupid. Thank you in advance.
This is my code:
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas> // create canvas to work with
<button onclick="fade(ctx)">Change the colour!</button>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //set context
ctx.rect(20, 20, 150, 100); // draw a rectangle
ctx.stroke(); // with border
ctx.fillStyle="#FFFF00"; // fill with yellow
ctx.fillRect(20,20,150,100);
function fade(ctx) { // fade function responsible for changing colour
var dom = getElementById(ctx), level = 1; // new object based on rectangle object, initial iterator is set to 1
function step() { // inner step function
var h = level.toString(16);
dom.fillStyle = '#FFFF' + h + h; // construct a new colour using h variable
if (level < 15) {
level += 1;
setTimeout(step, 100); // do this after every 100 ms
}
}
setTimeout(step, 100);
}
</script>
</body>
</html>
You almost have it with your code though. You are passing the context into the function already so no need for the getElementById(ctx) bit. In fact that will give you an error so remove that line from your code. Instead directly set the fillStyle on the ctx variable like this:
ctx.fillStyle = '#FFFF' + h + h;
and you also need to redraw the rectangle, so add this line:
ctx.fillRect(20,20,150,100);
after you set the colour. And that will do it.

Draw HTML5 Canvas pulse line

Hey guys I've been trying to wrap my head around the HTML5 Canvas animation but failed miserably I wanted to achieve the below figure by animating this custom shape in an interval of 10 seconds.
I've pretty much screwed the math of it so I ended up just writing every lineTo statement manually, tried Paul Irish's requestAnimationFrame at the end to animate the line but no luck.
Any help would be highly appreciated, here is
thelive demo
Thanks guys
It's not moving cause you are basically not moving anything - the same shape is drawn to the same position each iteration.
Here is a modified version which animates the pulse to the left (adjust dlt to change speed):
Modified fiddle here
var segX = canvas.width / 6;
var segY = canvas.height / 2;
function draw() {
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(0, segY);
for(var i = dlt, h = true; i < canvas.width + segX; i += segX) {
if (h) {
ctx.lineTo(i, segY);
ctx.lineTo(i, segY + segX);
} else {
ctx.lineTo(i, segY + segX);
ctx.lineTo(i, segY);
}
h = !h;
}
ctx.stroke();
dlt--;
if (dlt < -segX * 2) dlt = 0;
requestAnimFrame(draw);
}
You're basically needing a function that returns only 2 values--high and low.
Here's a function that returns only low/high values based on a period and oscillation values:
// squared wave
// p = period (how long it takes the wave to fully complete and begin a new cycle)
// o = oscillation (change in wave height)
function squareY(x) {
return( (x%p)<o?o:0 );
}
Demo: http://jsfiddle.net/m1erickson/A69ZV/
Example code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.lineWidth=3;
var p=30; // period
var o=15; // oscillation
var fps = 60;
var n=0;
animate();
function animate() {
setTimeout(function() {
requestAnimationFrame(animate);
// Drawing code goes here
n+=1.5;
if(n>300){
n=0;
}
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
for(var x=0;x<n;x++){
var y=squareY(x);
ctx.lineTo(x,y+50);
}
ctx.stroke();
}, 1000 / fps);
}
// squared sine
function squareY(x) {
return( (x%p)<o?o:0 );
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>

How to move canvas left to right with that data array?

Using same data array every time canvas moving but not continuously?
How to move canvas line left to right with that data array ?
if data array is completed use same data to continuously
here is my code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<canvas id="canvas" width="160" height="160" style="background-color: black;"></canvas>
<script type='text/javascript'>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle ="#dbbd7a";
ctx.fill();
var fps = 1000;
var n = 0;
drawWave();
var data = [
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
];
function drawWave() {
setTimeout(function () {
requestAnimationFrame(drawWave);
ctx.lineWidth="2";
ctx.strokeStyle='green';
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Drawing code goes here
n += 1.5;
if (n > 200) {
n = 0;
}
ctx.beginPath();
for (var x = 0; x < n; x++) {
ctx.lineTo(x, data[x]);
}
ctx.stroke();
}, 1000/fps);
}
</script>
</body>
</html>
There are some problems with your code:
The reason for your non-continuous delay at the end of your animation loop...
Your array has 140 elements but your code is trying to plot 200 elements. The delay is your code trying to plot (200-140) non-existent array elements.
If(n>=data.length) // not n>200 (there are only 140 data elements to process!)
Using setTimeout with a fps interval of 1000 is not achievable (60fps is a practical maximum).
Var fps=60; // not fps=1000 is too fast to be achieved
You are incrementing n by 1.5 each time. This will skip some of your data elements. If this is not your intention you should instead increment n by 1.
n+=1; // not n+=1.5 which will skip some of your data[] elements
You are clearing the canvas and completely redrawing the wave in each animation loop. This works, but instead, keep your previous canvas and add the additional line to plot your next [x,y]. Only clear after you have drawn all your data points.
ctx.beginPath();
ctx.moveTo(n-1,data[n-1]);
ctx.lineTo(n,data[n]);
ctx.stroke();
Here is a Fiddle: http://jsfiddle.net/m1erickson/vPXkm/
[Addition based on OP's new information]
After your further clarification, I might understand what you desire
I think you want to have a wave pattern originate new plots from the left part of the canvas and push the existing data to the right using animation. After all x,y are plotted from your data[] source, you want the plots to repeat at the beginning of data[].
So here is how you do that:
Resize the canvas to twice the width of your data[].
Plot your data across the canvas twice. (data[0-140] and then data[0-140] again).
Convert the canvas to an image.
Resize the canvas to the width of your data[].
Animate the image across the canvas with an increasing offsetX to give the illusion of movement.
When you run out of image, reset the offset.
This reset appears seamless since the image is repeated twice.
Here is new code and another Fiddle: http://jsfiddle.net/m1erickson/qpWrj/
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<canvas id="canvas" width="560" height="160" style="background-color: black;"></canvas>
<script type='text/javascript'>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var data = [
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,148
];
var fps = 30;
var offsetX=-data.length*2;
var waveImage;
createWaveImage();
function createWaveImage(){
// make the canvas double data.length
// and fill it with a background color
canvas.width=data.length*2;
ctx.fillStyle ="#dbbd7a";
ctx.strokeStyle="green";
ctx.lineWidth=2;
ctx.fillRect(0,0,canvas.width,canvas.height);
// plot data[] twice
ctx.beginPath();
ctx.moveTo(0,data[0]);
for(var x=1; x<data.length*2; x++){
var n=(x<data.length)?x:x-data.length;
ctx.lineTo(x,data[n]);
}
ctx.stroke();
// convert the canvas to an image
waveImage=new Image();
waveImage.onload=function(){
// resize the canvas to data.length
canvas.width=data.length;
// refill the canvas background color
ctx.fillStyle ="#dbbd7a";
ctx.fillRect(0,0,canvas.width,canvas.height);
// animate this wave image across the canvas
drawWave();
}
waveImage.src=canvas.toDataURL();
}
// animate the wave image in an endless loop
function drawWave() {
setTimeout(function () {
requestAnimationFrame(drawWave);
// Draw the wave image with an increasing offset
// so it appears to be moving
ctx.drawImage(waveImage,offsetX++,0);
// if we've run out of image, reset the offsetX
if((offsetX)>0){
offsetX=-data.length;
}
}, 1000/fps);
}
</script>
</body>
</html>

clearRect of canvas context does not clear the pixels

I want to make an animation with javascript and html canvas, just the make a rectangle move from the top of the window to the bottom, I use canvas.clearRect to clear all the pixel on the canvas, but, it seems this function does not work, the previously drawing was still there. here is all the code
<!DOCTYPE HTML>
<html>
<title>Jave script tetris by zdd</title>
<head>
<script>
function point(x, y)
{
this.x = x;
this.y = y;
}
function draw(timeDelta)
{
// Vertices to draw a square
var v1 = new point( 0, 0);
var v2 = new point(100, 0);
var v3 = new point(100, 100);
var v4 = new point( 0, 100);
this.vertices = [v1, v2, v3, v4];
// Get canvas context
var c = document.getElementById("canvas");
var cxt = c.getContext("2d");
// Clear the canvas, this does not work?
cxt.clearRect(0, 0, 800, 600);
// Move the piece based on time elapsed, just simply increase the y-coordinate here
for (var i = 0; i < this.vertices.length; ++i)
{
this.vertices[i].y += timeDelta;
}
cxt.moveTo(this.vertices[0].x, this.vertices[0].y);
for (var i = 1; i < this.vertices.length; ++i)
{
cxt.lineTo(this.vertices[i].x, this.vertices[i].y);
}
cxt.lineTo(this.vertices[0].x, this.vertices[0].y);
cxt.stroke();
}
var lastTime = Date.now();
function mainLoop()
{
window.requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.requestAnimationFrame(mainLoop);
var currentTime = Date.now();
var timeDelta = (currentTime - lastTime);
draw(timeDelta);
lastTime = currentTime;
}
</script>
</head>
<body>
<canvas id="canvas" width="800" height="600">
</canvas>
<script>
</script>
<button type="button" style="position:absolute; left:500px; top:600px; width:100px; height:50px;" class="start" onclick="mainLoop()">start</button>
</body>
</html>
and here is the result picture in Chrome, I want only one rectangle, but the clearRect function didn't clear the old rectangle, so..., how to fix this?
You are missing beginPath. Without it each box is actually part of the last box.
cxt.beginPath();
cxt.moveTo(this.vertices[0].x, this.vertices[0].y);
for (var i = 1; i < this.vertices.length; ++i) {
cxt.lineTo(this.vertices[i].x, this.vertices[i].y);
}
after adding that, the box seems to jiggle around, not sure if thats your intention.
Here's a fiddle: http://jsfiddle.net/6xbQN/
Good luck!

Categories