Глючная анимация холста при нажатии с помощью JavaScript

#javascript #animation #html5-canvas

#javascript #Анимация #html5-холст

Вопрос:

Я пытаюсь запускать простую анимацию каждый раз, когда пользователь нажимает на холст. Я уверен, что сделал что-то не так, поскольку анимация даже не срабатывает время от времени. Я никогда раньше не использовал анимацию холста и с трудом понимаю, как она должна быть построена в for цикле.

 fgCanvas.on('mousedown', function(e) {
  var cX = Math.round((e.offsetX - m) / gS),
      cY = Math.round((e.offsetY - m) / gS);

  clickDot({x:cX,y:cY});
});

function clickDot(data) {

  for (var i = 1; i < 100; i  ) {
    fctx.clearRect(0, 0, pW, pH);
    fctx.beginPath();
    fctx.arc(data.x * gS   m, data.y * gS   m, i/10, 0, Math.PI * 2);
    fctx.strokeStyle = 'rgba(255,255,255,'   i/10   ')';
    fctx.stroke();
  }
  requestAnimationFrame(clickDot);
}
 

Полный код здесь: http://jsfiddle.net/3Nk4A /

Другой вопрос в том, как можно замедлить анимацию или добавить некоторое ослабление, чтобы кольца рисовались медленнее к концу, когда они исчезают?

Ответ №1:

Вы можете использовать requestAnimationFrame plus easing functions для создания желаемого эффекта:

Демонстрация: http://jsfiddle.net/m1erickson/cevGf /

requestAnimationFrame создает цикл анимации сам по себе — поэтому нет необходимости использовать цикл for внутри цикла анимации requestAnimationFrame.

В своей простейшей форме этот цикл requestAnimationFrame будет анимировать ваш круг:

 var counter=1;

animate();

function animate(){

    // stop the animation after it has run 100 times
    if(counter>100){return;}

    // there's more animating to do, so request another loop
    requestAnimationFrame(animate);

    // calc the circle radius
    var radius=counter/10;

    // draw your circle

}
 

Чтобы ускорить или замедлить анимацию, вы можете использовать easings . Ослабления со временем изменяют значение (например, ваш радиус), но они изменяют это значение неравномерно. Ослабляет ускорение и замедление в течение всего времени анимации.

Роберт Пеннер создал отличный набор алгоритмов упрощения. Дэн Роджерс закодировал их на javascript:

https://github.com/danro/jquery-easing/blob/master/jquery.easing.js

Вы можете увидеть рабочие примеры его функций смягчения здесь:

http://easings.net/

Вот аннотированный код, использующий requestAnimationFrame plus easings для анимации ваших кругов.

 <!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
    #canvas{border:1px solid red;}
</style>
<script>
$(function(){

    // canvas related variables
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();

    // set the context styles
    ctx.lineWidth=1;
    ctx.strokeStyle="gold";
    ctx.fillStyle="#888";

    // variables used to draw amp; animate the ring
    var PI2=Math.PI*2;
    var ringX,ringY,ringRadius,ingCounter,ringCounterVelocity;

    // fill the canvas with a background color
    ctx.fillRect(0,0,canvas.width,canvas.height);

    // tell handleMouseDown to handle all mousedown events
    $("#canvas").mousedown(function(e){handleMouseDown(e);});

    // set the ring variables and start the animation
    function ring(x,y){
        ringX=x;
        ringY=y;
        ringRadius=0;
        ringCounter=0;
        ringCounterVelocity=4;

        requestAnimationFrame(animate);
    }

    // the animation loop
    function animate(){

        // return if the animation is complete
        if(ringCounter>200){return;}

        // otherwise request another animation loop
        requestAnimationFrame(animate);

        // ringCounter<100 means the ring is expanding
        // ringCounter>=100 means the ring is shrinking
        if(ringCounter<100){ 
            // expand the ring using easeInCubic easing
            ringRadius=easeInCubic(ringCounter,0,15,100); 
        }else{ 
            // shrink the ring using easeOutCubic easing
            ringRadius=easeOutCubic(ringCounter-100,15,-15,100);
        }

        // draw the ring at the radius set using the easing functions
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ctx.beginPath();
        ctx.arc(ringX,ringY,ringRadius,0,PI2);
        ctx.closePath();
        ctx.stroke();

        // increment the ringCounter for the next loop
        ringCounter =ringCounterVelocity;
    }


    //  Robert Penner's easing functions coded by Dan Rogers
    //
    //  https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
    //
    //  now=elapsed time,
    //  startValue=value at start of easing,
    //  deltaValue=amount the value will change during the easing,
    //  duration=total time for easing

    function easeInCubic(now, startValue, deltaValue, duration) {
      return deltaValue*(now/=duration)*now*now   startValue;
    }
    function easeOutCubic(now, startValue, deltaValue, duration) {
      return deltaValue*((now=now/duration-1)*now*now   1)   startValue;
    }


    // handle mousedown events
    function handleMouseDown(e){

      // tell the browser we'll handle this event
      e.preventDefault();
      e.stopPropagation();

      // calc the mouse position
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // animate a ring at the mouse position
      ring(mouseX,mouseY);

    }

}); // end $(function(){});
</script>
</head>
<body>
    <h4>Click in the canvas to draw animated circle with easings.</h4>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
 

Комментарии:

1. Отличный ответ! Спасибо.