Search code examples
javascriptanimationmathcanvaseasing

Javascript animation easing


I have a function which moves my canvas using an ease in aspect. The problem how ever is the canvas animation doesn't work. It just scrolls too far and what appears to be too fast as well.

This is my function which moves the camera to the location the user clicked on the canvas:

function moveCamera(e,parent){
    clearInterval(parent.scroll);

var mouseData       = mousePos(evt,parent); //get x:y relative to element           
var initial         = {'x':el.width/2,'y':el.height/2},
    target          = {'x':mouseData.x,'y':mouseData.y},            
    deltaX          = target.x-initial.x,
    deltaY          = target.y-initial.y,
    timeStart       = Date.now(),
    timeLength      = 800,
    x,y,deltaTime;

function update(){
    function fraction(t){
        x               = (target.x - initial.x) - (t*deltaX),
        y               = (target.y - initial.y) - (t*deltaY);
        camera.x       -= x;
        camera.y       -= y;
    }
    function easing(x) {
        return 0.5 + 0.5 * Math.sin((x - 0.5) * Math.PI);
    }   

    deltaTime = (Date.now() - timeStart) / timeLength;
    if (deltaTime > 1) {
        fraction(1);
    } else {
        fraction(easing(deltaTime));
    }   
}
parent.scroll = setInterval(update, 10);        
}

I have attatched a JSFiddle of the issue demonstrated: http://jsfiddle.net/p5xjmLay/ simply click on the canvas to scroll to that position, and you will see it goes a bit crazy.

I am wondering how to solve this so the camera offset changes correctly each time?


Solution

  • I changed a little bit your version and it seems that it is working, please try this:

        var el      = document.getElementById('canvas'),
        initial         = {'x':el.width/2,'y':el.height/2},
        ctx     = el.getContext('2d'),
        camera  = {'x':el.width/2,'y':el.height/2},
        box     = {'x':0,'y':0};
        var x,y,deltaTime;
    
        el.addEventListener('mousedown',function(e){moveCamera(e,this);},false);
    
    function moveCamera(e,parent){
            clearInterval(parent.scroll);
    
        var mouseData       = mousePos(e,parent);                       
            target          = {'x':mouseData.x,'y':mouseData.y},            
            deltaX          = target.x-initial.x,
            deltaY          = target.y-initial.y,
            timeStart       = Date.now(),
            timeLength      = 800;
    
    
        function update(){
            function fraction(t){
                x               = target.x - (initial.x + (t*deltaX)),
                y               = target.y - (initial.y + (t*deltaY));
    
                if (Math.abs(camera.x + x - target.x) > Math.abs(camera.x - target.x)) {
                    camera.x = target.x;
                    initial.x = target.x;
                } else {
                    camera.x       += x;                
                }
    
                if (Math.abs(camera.y + y - target.y) > Math.abs(camera.y - target.y)) {
                    camera.y = target.y;
                    initial.y = target.y;
                } else {
                    camera.y       += y;                
                }            
    
            }
            function easing(x) {
                return 0.5 + 0.5 * Math.sin((x - 0.5) * Math.PI);
            }   
    
            deltaTime = (Date.now() - timeStart) / timeLength;
            if (deltaTime > 1) {
                fraction(1);
            } else {
                fraction(easing(deltaTime));
            }
            draw(); 
        }
        parent.scroll = setInterval(update, 200);       
    }
    
    function mousePos(evt,el){
            var offsetX = 0,
                offsetY = 0;        
            do{
                offsetX += el.offsetLeft - el.scrollLeft;
                offsetY += el.offsetTop  - el.scrollTop;
            }while(el = el.offsetParent){
                return {'x':evt.pageX - offsetX, 'y':evt.pageY - offsetY}       
            }       
    }
    
    function draw(){
    
        ctx.clearRect(0,0,el.width,el.height);
    
        ctx.save();
        ctx.translate(camera.x,camera.y);     
    
        ctx.beginPath();
        ctx.rect(box.x-25, box.y-25,50,50);
        ctx.fillStyle = 'red';
        ctx.fill(); 
    
        ctx.restore();           
    }
    draw();