javascripthtmlcanvas

How can I create a motion blur effect by using canvas and javascript?


I have a virtual canvas with a drawn icon. This icon is dynamic so I can't make a motion blurred variant of this icon in Photoshop. I render this icon on the scene by this code:

function render (context) {
    context.drawImage(this.bufferedIcon, 0, 0);
}

Could you tell me if there is a simple way for creating the motion blur of this icon?


Solution

  • To do a simple motion blur use the globalAlpha

    var ctx = document.getElementById("can").getContext("2d");
    
    
    // dx and dy is the direction and speed of the blur
    function drawBlured(x,y,dx,dy){ // x,y current position, dx,dy delta x,y 
         var samples = 10;  // the number of samples. The greater the number the 
                           // better the effect but the slower the render
                           // over 100 samples and the dynamic range of colours 
                           // will begin to make it look bad
         dx /= samples;   // divide the speed by the number of samples
         dy /= samples;
         ctx.globalAlpha = 1/(samples/1.2);  // set the global alpha need to up the 
                                           // val a bit or it gets to dark
         for(var i = 0; i < samples; i++){  // draw  the image for each sample
             ctx.drawImage(image, x+i*dx,y+i*dy); // moving it as we go
         }
         ctx.globalAlpha = 1;  // restore alpha
    } // done;
    
    
    // code from here down is just for the snippet
    var posX= 200;
    var posY = 200;
    var speedX,speedY
    var destX,destY;
    
    // create somthing to blur
    var image = document.createElement("canvas");
    image.width = 100;
    image.height =100;
    var ctxS = image.getContext("2d");
    ctxS.fillStyle = "Black";
    ctxS.beginPath();
    ctxS.arc(50,50,48,0,Math.PI*2);
    ctxS.fill();
    
    ctxS.beginPath();
    ctxS.fillStyle = "#FF0";
    ctxS.arc(48,48,44,0,Math.PI*2);
    ctxS.fill();
    
    ctxS.fillStyle = "Black";
    ctxS.beginPath();
    ctxS.arc(25,25,20,0,Math.PI*2);
    ctxS.fill();
    ctxS.beginPath();
    ctxS.arc(75,25,20,0,Math.PI*2);
    ctxS.fill();
    ctxS.beginPath();
    ctxS.arc(50,80,10,0,Math.PI*2);
    ctxS.fill();
    
    ctxS.beginPath();
    ctxS.fillStyle = "white";
    ctxS.arc(25,25,16,0,Math.PI*2);
    ctxS.fill();
    ctxS.beginPath();
    ctxS.arc(75,25,16,0,Math.PI*2);
    ctxS.fill();
    
    ctxS.beginPath();
    ctxS.fillStyle = "black";
    ctxS.arc(25,25,8,0,Math.PI*2);
    ctxS.fill();
    ctxS.beginPath();
    ctxS.arc(75,25,8,0,Math.PI*2);
    ctxS.fill();
    
    
    var moving = false; // when moving
    var wait = 10;  // a pause timer
    function update(){
      ctx.clearRect(0,0,400,400);  // clear
      if(moving){  // draw moving
        drawBlured(posX,posY,speedX,speedY);
        posX += speedX;
        posY += speedY;
        wait -= 1;
        if(wait <= 0){ // done moving pause
          moving = false;
          wait = Math.random()*10+5;
        }
      }else{
        if(wait > 0){  // wait 
          wait -= 1;
          ctx.drawImage(image,posX,posY);
    
        }else{ // done waiting find a spot to move
          destX = (Math.random()*300)+50;
          destY = (Math.random()*300)+50;        
          speedX = (destX-posX)/5;
          speedY = (destY-posY)/5;        
          ctx.drawImage(image,posX,posY);
          wait = 5;
          moving = true;   // start movng
    
        }
      }
      setTimeout(update,50);  // do this 20 times a second
    }
    update();
    .canC {
      width:400px;
      height:400px;
     }
    <canvas class="canC" id="can" width=400 height=400></canvas>

    And don't use the filters for blur. They are mind numbingly inefficient, it may look good on your PC but on many machines it will die and look bad.