Frame by frame animation in HTML5 with canvas - html

I have a flash animation I am trying to convert to HTML5. Now I have taken out all the images. For example in the hand animation, I have taken images of all hand images. I have made the canvas with the base drawing but I don't know how to replace those images frame by frame.
function draw(){
var canvas = document.getElementById('canvas');
if(canvas.getContext){
// canvas animation code here:
var ctx = canvas.getContext('2d');
var lhs = new Image();
lhs.src = "images/left_hnd_1.png";
lhs.onload = function(){
ctx.drawImage(lhs, 293, 137);
}
} else {
// canvas unsupported code here:
document.getElementById('girl').style.display = "block";
}
}
Now I have three more frame for this image. left_hnd_2.png, left_hnd_3.png & left_hnd_4.png. I would've used one image but the difference in frames is way too much for it to be done with one image. How can I animate this with the time differences I want.
Any ideas would be greatly appreciated. Thanks!

Try this:
var imgNumber = 1;
var lastImgNumber = 4;
var ctx = canvas.getContext('2d');
var img = new Image;
img.onload = function(){
ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );
ctx.drawImage( img, 0, 0 );
};
var timer = setInterval( function(){
if (imgNumber>lastImgNumber){
clearInterval( timer );
}else{
img.src = "images/left_hnd_"+( imgNumber++ )+".png";
}
}, 1000/15 ); //Draw at 15 frames per second
An alternative, if you only have 4 images, would be to create a single huge image with all four in a 'texture atlas', and then use setTimeout or setInterval to call drawImage() with different parameters to draw different subsets of the image to the canvas.

This worked for me as well! For some reason, it didn't work when I had used the OP's opening code: function draw(){
However when I used: window.onload = function draw() { the animation plays on the canvas. I'm also using about 150 PNG images with an Alpha channel so this is a great way to bring 'video' or create composites to the iPad/iPhone. I confirm that it does work on iPad iOS 4.3.

Related

Play video on canvas and preserve the last frame/image on canvas

I'm using the following script code to draw a video on canvas:
$("#vPlayer").on('play', function (e) {
var canvas = $('canvas')[0];
var ctx = canvas.getContext('2d');
var $this = this;
canvas.width = 640;
canvas.height = 480;
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 0, 0, 640, 480);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
});
The code works well, but in my case, I want to change the video source (src attribute) of the video tag every 2 mins. When I set the src attr for the video and during the loading time for the video, the canvas displays white screen. How can I preserve the last image of video and do not clear the canvas?
It is a little bit weird because, when I don't set the width and height for the canvas, the last frame is preserved, but I need to set the size.
Every time you set the size of the canvas it will be cleared.
To avoid this you need to set the size at the "beginning", before you start drawing to it. In this case I would recommend you set it outside your event handler as well as the initializing of the canvas and context variable:
var canvas = $('canvas')[0];
var ctx = canvas.getContext('2d');
canvas.width = 640;
canvas.height = 480;
$("#vPlayer").on('play', function (e) {
var $this = this;
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 0, 0, 640, 480);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
});

Drawing repetitively one canvas without that edges become dark

I have this code that for some reason it should draw canvas many times (using setTimeout):
function drawImage() {
var img = new Image();
var canvas = document.getElementById("event");
var context = canvas.getContext("2d");
img.src = "../img/event.png";
img.onload = function () {
context.drawImage(img, 0, 0);
}
setTimeout(drawImage, 3000);
}
but it cause dark edge as draw more times as this:
Is it possible to prevent edges become dark in repetitively drawing?
As long as the image has an alpha-channel you cannot avoid this when re-painting it over and over without some mechanism to reset the alpha values drawn.
The reason for this is that the alpha-value for that pixel will accumulate so when you draw a non-opaque edge (or anti-aliased edge) on top of each other the value for the alpha channel will be added to the value already drawn resulting in that the edge will be more and more visible.
There are fortunately a couple of ways to avoid this:
A) If you want to keep the alpha-channel in the image use clearRect before drawing the image.
context.clearRect(0, 0, img.width, img.height);
context.drawImage(img, 0, 0);
This will clear the canvas and the alpha channel.
ONLINE DEMO
B) If alpha channel is not important save out the image without any alpha-channel (use PNG with transparency off or use JPEG).
Also a note to your loop in the example - this is not a good way to redraw an image as you are initiating a load/cache check as well as image decoding each time.
You can modify your code as this (adopt as you please):
var canvas = document.getElementById("event");
var context = canvas.getContext("2d");
var img = document.createElement('img'); // due to chrome bug
img.onload = drawImage; // set onload first
img.src = "../img/event.png"; // src last..
function drawImage() {
context.clearRect(0, 0, img.width, img.height);
context.drawImage(img, 0, 0);
setTimeout(drawImage, 3000);
}

How to swap images on HTML without libraries (like z-index)

I have a question !
In a html5 canvas, I create an "x" number of images. The last image created is always above the other. Is it possible to swap the depths of the images without the need for libraries? (I do not intend to reverse the order of the variables)
I want somethin like this (without kinetic):
http://www.html5canvastutorials.com/kineticjs/html5-canvas-shape-layering-with-kineticjs/
so, here is the code I'm using:
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = "image1.png";
var imageObj2 = new Image();
imageObj2.onload = function() {
context.drawImage(imageObj2, 40, 30);
};
imageObj2.src = "image2.png";
/* I want to put "Image1.png" over "Image2.png" dynamically, for example, pressing a button, all this after render on the canvas */
Draw the furtherest images first. It might help to put the images in an array so you can just loop through them.
Otherwise, in the case of your example, this will fix it as you are drawing context.drawImage(imageObj, 69, 50); last. Think of it as if you would draw it on paper; what you draw last is above what you have already drawn.
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj2 = new Image();
imageObj2.onload = function() {
context.drawImage(imageObj2, 40, 30);
};
imageObj2.src = "image2.png";
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = "image1.png";
The order you draw the images matters. You will need to draw the images in the back first, then draw the closer ones.
Why don't you create a canvas object for every image and either show / hide them or adjust the z-index?

html5 getImageData then putImageData results in fading image

I'm very new to Html5 and I was wondering if someone could shed some light on this:
<script type="text/javascript">
window.onload = function () {
var canvas = document.getElementById('canvas'); //682 x 111 pixel canvas
var context = canvas.getContext('2d');
var image = new Image();
image.src = "/Content/ImageTestOne/logo-for-dissolve.png"; //682 x 111 pixel image
image.onload = function () { context.drawImage(image, 0, 0); drawFrame(); };
function drawFrame() {
window.requestAnimationFrame(drawFrame, canvas);
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
//Do something to some pixels here that persists over time
context.clearRect(0, 0, canvas.width, canvas.height);
context.putImageData(imageData, 0, 0);
};
};
</script>
According to my limited knowledge of Html5 this code should do nothing except continually display the "image". But instead the image quite rapidly burns out to almost white which suggests that the imageData is changed slightly each time it is either read from or written to the canvas...
Basically I wanted to fade the image where the mouse was located so that a background image shows through as the mouse is moved around. Is there a way around this or am I going to have to become a little more creative with the process? Is there anyway I can manipulate the "image" ImageData rather than getting it from the canvas each time?
Thanks in advance, I've tried using jpg and png and loading into DOM rather than via image.src but they all have the same issue.
Using the latest Chrome btw.
Here is the setup for the requestionAnimationFrame to handle a range of browsers with a fail over to SetTimeout:
(!window.requestAnimationFrame)
{
window.requestAnimationFrame = (window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
return window.setTimeout(callback, 1000/60);
});
}
Here is the code for the canvas
<canvas id="canvas" width="682" height="111"></canvas>
That's all the code for this.
putImageData() and getImageData() can be lossy. There's a note in the spec about this:
Due to the lossy nature of converting to and from premultiplied alpha
color values, pixels that have just been set using putImageData()
might be returned to an equivalent getImageData() as different values.
See also this related question:
Why does HTML Canvas getImageData() not return the exact same values that were just set?
I have tried also to apply this to my game where in im going to manipulate the selected pixels to have effect but It doesn't give me the expected result
here is some sample code that i used to manipulate the pixel to change
get image information and store
var img = context.getImageData(0,0, width, height)
var imgdata = img.data
var len = imgdata.length
loop to all data and manipulate pixel information
var i = 0;
for(i; i<leng; i++) {
var red = imgdata[i]
var green = imgadata[i+1]
var blue = imgdata[i+2]
var alpha = imgdata[i+3]
imgdata[i] = new value
imgdata[i+1] = new value
imgdata[i+2] = new value
imgdata[i+3] = new value
}
context.putImageData(img, 0,0)
then create animation frame to see effect
requestAnimationFrame is an experimental feature (june 2012) that uses time based frame access. The reason for this is avoid latency in animations.
I suggest you take a look at this Moz article.

How to change the opacity (alpha, transparency) of an element in a canvas element?

Using the HTML5 <canvas> element, I would like to load an image file (PNG, JPEG, etc.), draw it to the canvas completely transparently, and then fade it in. I have figured out how to load the image and draw it to the canvas, but I don't know how to change its opacity.
Here's the code I have so far:
var canvas = document.getElementById('myCanvas');
if (canvas.getContext)
{
var c = canvas.getContext('2d');
c.globalAlpha = 0;
var img = new Image();
img.onload = function() {
c.drawImage(img, 0, 0);
}
img.src = 'image.jpg';
}
Will somebody please point me in the right direction like a property to set or a function to call that will change the opacity?
I am also looking for an answer to this question, (to clarify, I want to be able to draw an image with user defined opacity such as how you can draw shapes with opacity) if you draw with primitive shapes you can set fill and stroke color with alpha to define the transparency. As far as I have concluded right now, this does not seem to affect image drawing.
//works with shapes but not with images
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
I have concluded that setting the globalCompositeOperation works with images.
//works with images
ctx.globalCompositeOperation = "lighter";
I wonder if there is some kind third way of setting color so that we can tint images and make them transparent easily.
EDIT:
After further digging I have concluded that you can set the transparency of an image by setting the globalAlpha parameter BEFORE you draw the image:
//works with images
ctx.globalAlpha = 0.5
If you want to achieve a fading effect over time you need some kind of loop that changes the alpha value, this is fairly easy, one way to achieve it is the setTimeout function, look that up to create a loop from which you alter the alpha over time.
Some simpler example code for using globalAlpha:
ctx.save();
ctx.globalAlpha = 0.4;
ctx.drawImage(img, x, y);
ctx.restore();
If you need img to be loaded:
var img = new Image();
img.onload = function() {
ctx.save();
ctx.globalAlpha = 0.4;
ctx.drawImage(img, x, y);
ctx.restore()
};
img.src = "http://...";
Notes:
Set the 'src' last, to guarantee that your onload handler is called on all platforms, even if the image is already in the cache.
Wrap changes to stuff like globalAlpha between a save and restore (in fact use them lots), to make sure you don't clobber settings from elsewhere, particularly when bits of drawing code are going to be called from events.
Edit: The answer marked as "correct" is not correct.
It's easy to do. Try this code, swapping out "ie.jpg" with whatever picture you have handy:
<!DOCTYPE HTML>
<html>
<head>
<script>
var canvas;
var context;
var ga = 0.0;
var timerId = 0;
function init()
{
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
timerId = setInterval("fadeIn()", 100);
}
function fadeIn()
{
context.clearRect(0,0, canvas.width,canvas.height);
context.globalAlpha = ga;
var ie = new Image();
ie.onload = function()
{
context.drawImage(ie, 0, 0, 100, 100);
};
ie.src = "ie.jpg";
ga = ga + 0.1;
if (ga > 1.0)
{
goingUp = false;
clearInterval(timerId);
}
}
</script>
</head>
<body onload="init()">
<canvas height="200" width="300" id="myCanvas"></canvas>
</body>
</html>
The key is the globalAlpha property.
Tested with IE 9, FF 5, Safari 5, and Chrome 12 on Win7.
This suggestion is based on pixel manipulation in canvas 2d context.
From MDN:
You can directly manipulate pixel data in canvases at the byte level
To manipulate pixels we'll use two functions here - getImageData and putImageData.
getImageData usage:
var myImageData = context.getImageData(left, top, width, height);
The putImageData syntax:
context.putImageData(myImageData, x, y);
Where context is your canvas 2d context, and x and y are the position on the canvas.
So to get red green blue and alpha values, we'll do the following:
var r = imageData.data[((x*(imageData.width*4)) + (y*4))];
var g = imageData.data[((x*(imageData.width*4)) + (y*4)) + 1];
var b = imageData.data[((x*(imageData.width*4)) + (y*4)) + 2];
var a = imageData.data[((x*(imageData.width*4)) + (y*4)) + 3];
Where x is the horizontal offset, y is the vertical offset.
The code making image half-transparent:
var canvas = document.getElementById('myCanvas');
var c = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
c.drawImage(img, 0, 0);
var ImageData = c.getImageData(0,0,img.width,img.height);
for(var i=0;i<img.height;i++)
for(var j=0;j<img.width;j++)
ImageData.data[((i*(img.width*4)) + (j*4) + 3)] = 127;//opacity = 0.5 [0-255]
c.putImageData(ImageData,0,0);//put image data back
}
img.src = 'image.jpg';
You can make you own "shaders" - see full MDN article here
You can. Transparent canvas can be quickly faded by using destination-out global composite operation. It's not 100% perfect, sometimes it leaves some traces but it could be tweaked, depending what's needed (i.e. use 'source-over' and fill it with white color with alpha at 0.13, then fade to prepare the canvas).
// Fill canvas using 'destination-out' and alpha at 0.05
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
ctx.beginPath();
ctx.fillRect(0, 0, width, height);
ctx.fill();
// Set the default mode.
ctx.globalCompositeOperation = 'source-over';
I think this answers the question best, it actually changes the alpha value of something that has been drawn already. Maybe this wasn't part of the api when this question was asked.
Given 2d context c.
function reduceAlpha(x, y, w, h, dA) {
let screenData = c.getImageData(x, y, w, h);
for(let i = 3; i < screenData.data.length; i+=4){
screenData.data[i] -= dA; //delta-Alpha
}
c.putImageData(screenData, x, y );
}
Set global Alpha draw the object that has opacity then set back to normal.
//////////////////////// circle ///////////////////////
ctx.globalAlpha = 0.75;
ctx.beginPath();
ctx.arc(x1, y1, r1, 0, Math.PI*2);
ctx.fillStyle = colour;
ctx.fill();
ctx.closePath();
ctx.globalAlpha = 1;
How i made it..on canvas i first draw rect in a selfrun function 0,0,canvas.width,canvas.height as a background of canvas and i set globalAlpha to 1 .then i draw other shapes in ather own functions and set their globalAlpha to 0.whatever number they dont affect each other even images.
Like Ian said, use c.globalAlpha = 0.5 to set the opacity, type up the rest of the settings for the square, then follow up with c.save();. This will save the settings for the square then you can c.rect and c.fillStyle the square how you want it. I chose not to wrap it with c.restore afterwards and it worked well
If you use jCanvas library you can use opacity property when drawing. If you need fade effect on top of that, simply redraw with different values.
You can't. It's immediate mode graphics. But you can sort of simulate it by drawing a rectangle over it in the background color with an opacity.
If the image is over something other than a constant color, then it gets quite a bit trickier. You should be able to use the pixel manipulation methods in this case. Just save the area before drawing the image, and then blend that back on top with an opacity afterwards.