27.12.2014

С новым годом! И немного анимации с помощью HTML5 Canvas.

 

Хочу привести простой пример использования возможностей рисования и анимации с помощью HTML5. Собственно, то, что получится в итоге, вы можете наблюдать чуть выше (разумеется, если вы не отключили JavaScript). Для того, что бы получить такой результат -  будем использовать элемент canvas, который включен в спецификацию HTML5, и предназначен для рисования.

Первым делом нужно создать страницу и поместить на нее элемент canvas: 

<!DOCTYPE html>
<html>
<body>
  <canvas id="myCanvas" width="200" height="200"></canvas>
  <script>
  </script>
 </body>
</html>

По умолчанию, размер области для рисования элемента canvas - 300px x 150px. Поскольку нам хватит и меньше - задаем размер 200px x 200px.  Теперь нужно написать скрипт, который будет рисовать нашу новогоднюю елку. Соответственно, весь дальнейший код добавим в тег <script> на только что созданной странице. Начнем с рисования самой елки:

 var colorShift = 0;

  //рисуем елку
  function drawTree() {
 
            var canvas  = document.getElementById("myCanvas");
            var ctx = canvas.getContext("2d");

            //рисуем листву и нижнюю часть
            ctx.fillStyle = "green";
            ctx.fillRect(60, 50, 40, 90);
            ctx.fillRect(40, 110, 80, 40);

            a = 60;
            b = 10;
            for (var i = 0; i < 4; i++) {
                drawLeaf(-20 + a - (i * 10), b + (i * 30), ctx, "left");
                drawLeaf(20 + a + (i * 10), b + (i * 30), ctx, "right");
            }
            ctx.fillStyle = "brown";
            ctx.fillRect(70, 150, 20, 20);

            drawCircles(ctx);
           
            drawText(ctx);

    } 

    //нарисовать листву
    function drawLeaf(x, y, ctx, style) {
        
        ctx.beginPath();
        ctx.fillStyle = "green";
        if (style == "right") {
            ctx.moveTo(x, y);
            ctx.lineTo(x + 40, y + 40);
            ctx.lineTo(x, y + 40);
        } else {
            ctx.moveTo(x + 40, y);
            ctx.lineTo(x, y + 40);
            ctx.lineTo(x + 40, y + 40);
        }
        ctx.fill();
    }

    //текст на елке
    function drawText(ctx){
    	ctx.font="19px  Impact";
    	ctx.fillStyle = 'gold';
        ctx.fillText("2015",61,90);
    }

    function drawCircles(ctx) {

        var radius = 3;

    	drawCircle(90,50,radius, getColor1(),ctx);
    	drawCircle(80,30,radius,getColor2(),ctx);
    	drawCircle(70,60,radius,getColor3(),ctx);
    	drawCircle(90,65,radius,getColor4(),ctx);
    	drawCircle(70,100,radius,getColor5(),ctx);
    	drawCircle(95,110,radius,getColor4(),ctx);
    	drawCircle(80,120,radius,getColor3(),ctx);
    	drawCircle(110,120,radius,getColor2(),ctx);
    	drawCircle(95,135,radius,getColor1(),ctx);
    	drawCircle(49,110,radius,getColor5(),ctx);
    	drawCircle(60,120,radius,getColor3(),ctx);
    	drawCircle(60,135,radius,getColor2(),ctx);
    }


    function drawCircle(x,y,radius,color,context){
    	
         context.beginPath();
         context.arc(x, y, radius, 0, 2 * Math.PI, false);
         context.fillStyle = color;
         context.fill();
         context.lineWidth = 1;
         context.strokeStyle = color;
         context.stroke();
    }

Функция drawTree предназначена для рисования всего рисунка, то есть всей елки. Функция drawLeaf - для рисования ветвей, а функции drawCircles и drawCircle - для рисования кругов на елке, которые будут являться "гирляндой" на нашей елке. Функция drawText рисует текст "2015". Функции getColor1(), getColor2() ... - это функции получения цвета каждого элемента "гирлянды", которые мы скоро добавим. Переменная colorShift нужна для обеспечения анимации, которую мы тоже сейчас добавим. 

    function getColor1(){
    	return "rgba("+colorShift+", 90,50, 1)";
    }

    function getColor2(){
    	return "rgba(100,"+colorShift+",150, 1)";
    }

    function getColor3(){
    	return "rgba(155, 200, "+colorShift+", 1)";
    }

    function getColor4(){
    	return "rgba("+colorShift+", 100,200, 1)";
    }

    function getColor5(){
    	return "rgba("+colorShift+", 90,10, 1)";
    }

Напишем несколько функций, которые возвращают различные значения цвета, эти цвета мы будем использовать для элементов "гирлянды". В каждой из функций, зададим значение цвета в формате RGBA, причем один из компонетов цвета будет задаваться с помощью переменной colorShift, которая будет изменяться в процессе анимации. Таким образом, получится плавное псевдослучайное изменение цвета каждого элемента "гирлянды".  Наша елка почти готова, осталось добавить саму анимацию, с помощью которой мы создадим нечто похожее на гирлянду, которая плавно переливается разными цветами:

function animate() {

       reqAnimFrame = window.mozRequestAnimationFrame    ||
                   window.webkitRequestAnimationFrame ||
                   window.msRequestAnimationFrame     ||
                   window.oRequestAnimationFrame;

       reqAnimFrame(animate);

       colorShift = colorShift + 1; 
       
       if (colorShift == 255){
       	colorShift = 0;
       }

       drawTree();
     }
      animate();

Теперь самое интересное - анимация. Для этого будем использвать функцию RequestAnimationFrame. Логично, что для обеспечения анимации нужно перерисовывать изображение. Для этого можно воспользоваться функцией SetInterval (SetTimeout), однако сейчас рекомендуется использовать функцию RequestAnimationFrame. 

Во-первых, SetTimeout не принимает во внимание то, что еще происходит в браузере. Страница может, например, находится в неактивной вкладке браузера. При этом она будет использовать ресурсы процессора не взирая на это.

Кстати умный Chrome делает setInterval и setTimeout равным 1fps в скрытых вкладках.. но, насколько я знаю, так пока делает только chrome. 

Во-вторых, SetTimeout требует перерисовки страницы не в то же время, когда это делает ваш компьютер (а он делает это регулярно). Это означает, что ваш бедный браузер должен синхронизировать вашу горе-анимацию с обновлением всего экрана, и если ее частота не синхронизирована с обновлением всего экрана, это может потребовать больше вычислительной мощности. А это загрузка процессора, нагрев, шум куллера, расход батареи мобильных девайсов.. и т.п
Чтобы преодолеть эти проблемы, Mozilla (создатели Firefox) предложил функцию requestAnimationFrame, которая впоследствии была принята и усовершенствована командой WebKit (Chrome и Safari). Она обеспечивает встроеный API для запуска любых типов анимации в браузере (DOM элементов, canvas, WebGL и др.) [*] 

В функции animate используем одну из версий функции RequestAnimationFrame, в зависимости от того, какой браузер используется. И при каждом вызове изменяем значение переменной colorShift, с помощью чего обеспечивется изменение цвета "гирлянды". 



Теги: html5 web javascript

comments powered by Disqus