Hello developers! Thank you for reading my article. Today, I explain how to make animation with canvas as below. Responsive is not supported , but you can make it with only 70 lines of javascript.
Here, you can check it.
Before explaining detail, let's check the required knowledge and principle about web canvas animation. If you well know, skip this section.
You can check the sample here, the animation is running correctly and I don't use movie. This animation is played on canvas element with javascript.
Waving images is difficult for using only div tag or img tag. The animation needs canvas element.
Animation is doing "Erase the image, redraw, erase, redraw ..." at an invisible speed. Also, js draws after erasing the bottom of the image with a transparent wavy line. And to make the wave look like it is flowing, I use a trigonometric function to calculate the part to be erased in a wavy shape.
It is hard to understand, so let's make figures.
If you increase θ of sin(θ) each 1~6 process is repeated, it looks like a different wave swells each time. Implement the wave animation in this way.
Canvas is one of the HTML5 elements. It can draw 2D shapes, graphics and animation with javaScript. It makes complex animation and shapes.
At first, let's display image on canvas element. This time, put the below files at the same level.
sample.jpg is trimed with 1:2 (verical:horizon).Yeah, let's develop! First step, create HTML as below.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>waving image</title>
<style>
*{
margin:0;
padding:0;
}
main{
background:rgb(240, 255, 255);;
}
</style>
</head>
<body>
<main>
<canvas id="canvas"></canvas>
</main>
<script src="./app.js"></script>
</body>
</html>
Prepare canvas element which has id to detect with javascript. Next step, write js file.
Write app.js code as below.
function initAnimation(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var imagePath = ('./sample.jpg');
var image = new Image();
image.src = imagePath;
canvas.width = Number(window.innerWidth);
canvas.height = Number(canvas.width/2);
image.onload = function(){
ctx.drawImage(image,0,0,image.width,image.height,0,0,canvas.width,canvas.height);
}
}
This function get canvas element from HTML and context instance to operate with javascript. After that, various process are made for this ctx (drawing context instance).
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
and
var imagePath = ('./sample.jpg');
var image = new Image();
image.src = imagePath;
canvas.width = Number(window.innerWidth);
canvas.height = Number(canvas.width/2);
image.onload = function(){
ctx.drawImage(image,0,0,image.width,image.height,0,0,canvas.width,canvas.height);
}
Set image's path to src property using Image Object. Set canvas size with canvas.width
and canvas.height
. So image ratio is 1:2, make canvas's ratio same.
image.onload
run callback after image loaded.
drawImage()
method renders image on canvas。
drawImage()
must be run after image.onload
to set image.
Anyway, run script. Image will be rendered even you don't use img tag.
drawImage()
draws image on canvas specify range. If you render image at whole canvas, you should enter all arguments.(MDN)
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
Let me explain about arguments.
Image instance as well target image.
Like this. In my example this time,
ctx.drawImage(
image,
0,0,image.width,image.height,
0,0,canvas.width,canvas.height
);
0,0,image.width,image.height
cut image from (0,0) coordinate point of the image by the image's width and height. That same as to cut whole image.
If you set 0,0,image.width/2,image.height/2
, canvas displays 1/4 size of original image.
0,0,canvas.width,canvas.height
paste the image on canvas from (0,0) coordinate point by the canvas's width and height.
When you change ratio on code, you will well understand what I write above.
Let's cut image by wave shape. As I explained previwe of cutting above, draw square image which bottom line is wave shape and fill there transparent. Add below codes to image.onload
function.
image.onload = function(){
initDraw();
}
var canvasEndX = canvas.width;
var canvasEndY = canvas.height;
var waveStartPoint = canvasEndY-150;
var amplitude = 30;
var period = 1000;
var degree = 0;
function initDraw(){
imageSet(image,canvasEndX,canvasEndY);
waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);
}
function imageSet(imageObj,canvasEndX,canvasEndY){
var imgWidth = imageObj.width;
var imgHeight = imageObj.height;
ctx.drawImage(image,0,0,imgWidth,imgHeight,0,0,canvasEndX,canvasEndY);
}
function waveDrawing(waveStartPoint,canvasEndX,canvasEndY,deg,am,tp){
var waveStartY = waveStartPoint;
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
ctx.moveTo(0, waveStartY);
for (var x=0; x <= canvasEndX; x+= 1) {
var y = -am*Math.sin((Math.PI/tp)*(deg+x));
ctx.lineTo(x, y+waveStartY);
}
ctx.lineTo(canvasEndX,canvasEndY);
ctx.lineTo(0,canvasEndY);
ctx.closePath();
ctx.fillStyle = "rgba(255,255,255,1)"; //opacity 1
ctx.fill();
}
I make new three functions there.
I explain these.
function imageSet(imageObj,canvasEndX,canvasEndY){
var imgWidth = imageObj.width;
var imgHeight = imageObj.height;
ctx.drawImage(image,0,0,imgWidth,imgHeight,0,0,canvasEndX,canvasEndY);
}
This function just render image on canvas. When you set image object, canvas height and width at artguments, function use drawImage()
to render image.
waveDrawing()
has process cutting image by wave shape.
function waveDrawing(waveStartPoint,canvasEndX,canvasEndY,deg,am,tp){
var waveStartY = waveStartPoint;
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
ctx.moveTo(0, waveStartY);
for (var x=0; x <= canvasEndX; x+= 1) {
var y = -am*Math.sin((Math.PI/tp)*(deg+x));;
ctx.lineTo(x, y+waveStartY);
}
ctx.lineTo(canvasEndX,canvasEndY);
ctx.lineTo(0,canvasEndY);
ctx.closePath();
ctx.fillStyle = "rgba(255,255,255,1)"; //opacity 1
ctx.fill();
}
Each parameters mean
You don't have to think hard. More incresing am
higher wave. More increasing tp
, gentle wave.
And ctx is the canvas instance you define above. It is global vars at this time.
var waveStartY = waveStartPoint;
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
ctx.moveTo(0, waveStartY);
ctx.globalCompositeOperation = "destination-out";
is very important to make the image transparent. MDN
globalCompositeOperation
configure how the browser renders superposed shapes on the canvas. Remenber the below image.
This process fills the image by transparent within the area surrounded by a red line. When that, the already rendered image and the wave shape filled transparent are superposed.
The configure renderers only parts whitch the image and the shape are not superposed. So particular area will be transparent like no.5 of the above figure
ctx.beginPath();
ctx.moveTo(0, waveStartY);
for (var x=0; x <= canvasEndX; x+= 1) {
var y = -am*Math.sin((Math.PI/tp)*(deg+x));;
ctx.lineTo(x, y+waveStartY);
}
ctx.lineTo(canvasEndX,canvasEndY);
ctx.lineTo(0,canvasEndY);
ctx.closePath();
Next, I specify the cut range. That is 1~4 of the above figure. In this section, the word 'path' is often used. If you use Illustrator or Photoshop, you know it. Javascript also uses 'path' and specify the cut range.
Just in the case for who do not know 'path', I explain it. The path is the point that defines the shape. Drawing lines from point to point makes the shape. For example, the square has 4 points(edge) and, writing in one stroke from point to point makes the square. You define the path of writing in one stroke and position on the code.
ctx.beginPath()
starts setting paths.ctx.moveTo(X,Y)
moves the path to specify coordinates.ctx.lineTo(nextX,nextY)
draw a line and move next coordinates.ctx.closePath()
declear to end setting path.In this article case,
0
is the left edge of the image (X = 0) and waveStartY
is a start point for the wave.for
and write the trigonometric function has x coordinates as sin argument, set paths and the paths.You just fill after you select the area by above method.
ctx.fillStyle = "rgba(255,255,255,1)"; //opacity 1
ctx.fill();
fillStyle
configures the color to fill. If you set globalCompositeOperation = "destination-out";`, there no problem to use any colors.
fill()method fills the area surrounded paths. Because
globalCompositeOperation = "destination-out";`` is configured, the parts which the image and the shape are not superposed remains, but superposed area will be transparent.
If you come here, you get the image that is cut with the wave.
Using defined functions imageSet()
and waveDrawing()
, set a loop fucntion.
function loop(){
setInterval(function(){
imageSet(image,canvasEndX,canvasEndY);
waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);
degree += 12; // 12 is feeling.
},30)
}
The most important point is adding the number of angle with waveDrawing()
like degree +=4
. Thus, the wave is animated. More increase degrees, more fast the wave. If you set over 50, it will be rough waves.
And image.onload
fires the loop()
function.
image.onload = function(){
initDraw();
loop();
}
Whole code is theb below.
window.onload = init();
function init(){
initAnimation();
function initAnimation(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var imagePath = ('./sample.jpg');
var image = new Image();
image.src = imagePath;
//set canvas width and height
canvas.width = Number(window.innerWidth);
canvas.height = Number(canvas.width/2);
image.onload = function(){
initDraw();
loop();
}
var canvasEndX = canvas.width;
var canvasEndY = canvas.height;
var waveStartPoint = canvasEndY-150;
var amplitude = 30;
var period = 600;
var degree = 0;
function initDraw(){
imageSet(image,canvasEndX,canvasEndY);
waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);
}
function loop(){
setInterval(function(){
imageSet(image,canvasEndX,canvasEndY);
waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);
degree += 12;
},30)
}
function imageSet(imageObj,canvasEndX,canvasEndY){
var imgWidth = imageObj.width;
var imgHeight = imageObj.height;
ctx.globalCompositeOperation = "destination-over";
ctx.drawImage(image,0,0,imgWidth,imgHeight,0,0,canvasEndX,canvasEndY);
}
function waveDrawing(waveStartPoint,canvasEndX,canvasEndY,deg,am,tp){
var waveStartY = waveStartPoint;
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
ctx.moveTo(0, waveStartY);
for (var x=0; x <= canvasEndX; x+= 1) {
var y = -am*Math.sin((Math.PI/tp)*(deg+x));
ctx.lineTo(x, y+waveStartY);
}
ctx.lineTo(canvasEndX,canvasEndY);
ctx.lineTo(0,canvasEndY);
ctx.closePath();
ctx.fillStyle = "rgba(255,255,255,1)"; //opacity 1
ctx.fill();
}
}
}
In this case,
var amplitude = 30;
var period = 600;
function loop(){
...
degree += 12;
},30)
}
amplitude
defines the wave's height and period
is the width of the wave and degree +=
is velocity. On the other, by changing the trigonometric function you configured in waveDrawing()
, you can render
That is all how to make the image waved. Canvas element can render complex animation like this.
コメント
コメント読み込み中..