0

i want to add elasticity to the existing animation by making the circle and line return to its original position when dragged.

I have tried using mouseclick and mousedown, but not working. Here's the jsfiddle

https://jsfiddle.net/vinito/byw7to95/

<!DOCTYPE html>
<html>
<head>

<style type="text/css">
    #canvasOne
    {
        border: 1px solid black;
    }
</style>
<script src="jquery-1.7.2.min.js" type="text/javascript"></script>
</head>
<body>
    <div align="center">
        <canvas id="canvasOne" width="950" height="700">
        </canvas>
    </div>

    <script type="text/javascript">

    var myCanvas = document.getElementById("canvasOne");
    var myContext = myCanvas.getContext("2d");

    init();

    var numShapes;
    var shapes;
    var dragIndex;
    var dragging;
    var mouseX;
    var mouseY;
    var dragHoldX;
    var dragHoldY;
    var timer;
    var targetX;
    var targetY;
    var easeAmount;
    var bgColor;

    function init()
    {
        numShapes = 5;              
        shapes = [];

        makeShapes();
        drawScreen();   
        myCanvas.addEventListener("mousedown", mouseDownListener, false);   
    }

    function makeShapes()
    {
        var tempX;
        var tempY;
        var tempRad;        
        var tempGrad;
        var gradFactor = 2;

        for(var i = 0; i < numShapes; i++)
        {           
            //random position
            tempRad = 40;
            var centerX = myCanvas.width/2;
            var centerY = myCanvas.height/2;

            if(i == 0)
            {
                tempX = centerX
                tempY = centerY;
            }
            else
            {
                //tempX = Math.random() * (myCanvas.width - tempRad);
                //tempY = Math.random() * (myCanvas.height - tempRad);
                //150 can be actual radius in degrees
                tempX = centerX + 250 * Math.cos(2 * Math.PI * i / numShapes);
                tempY = centerY + 250 * Math.sin(2 * Math.PI * i / numShapes);
            }

            tempColor = "#4285F4";
            tempShape = {x: tempX, y: tempY, rad: tempRad, color: tempColor};

            shapes.push(tempShape);         
        }       
    }

    function mouseDownListener(evt)
    {
        var highestIndex = -1;

        var bRect = myCanvas.getBoundingClientRect();
        mouseX = (evt.clientX - bRect.left) * (myCanvas.width/bRect.width);
        mouseY = (evt.clientY - bRect.top) * (myCanvas.height/bRect.height);

        for(var i = 0; i < numShapes; i++)
        {
            if(hitTest(shapes[i], mouseX, mouseY))
            {
                dragging = true;
                if(i > highestIndex)
                {
                    dragHoldX = mouseX - shapes[i].x;
                    dragHoldY = mouseY - shapes[i].y;
                    highestIndex = i;
                    dragIndex = i;
                }               
            }
        }

        if(dragging)
        {
            window.addEventListener("mousemove", mouseMoveListener, false);
        }

        myCanvas.removeEventListener("mousedown", mouseDownListener, false);
        window.addEventListener("mouseup", mouseUpListener, false);

        if(evt.preventDefault)
        {
            evt.preventDefault;
        }

        return false;
    }

    function mouseUpListener(evt)
    {
        myCanvas.addEventListener("mousedown", mouseDownListener, false);
        window.removeEventListener("mouseup", mouseUpListener, false);

        if(dragging)
        {
            dragging = false;
            window.removeEventListener("mousemove", mouseMoveListener, false);
        }
    }

    function mouseMoveListener(evt)
    {
        var shapeRad = shapes[dragIndex].rad;

        var minX = shapeRad;
        var maxX = myCanvas.width - shapeRad;

        var minY = shapeRad;
        var maxY = myCanvas.height - shapeRad;

        //get mouse position correctly
        var bRect = myCanvas.getBoundingClientRect();
        mouseX = (evt.clientX - bRect.left)*(myCanvas.width / bRect.width);
        mouseY = (evt.clientY - bRect.top)*(myCanvas.height / bRect.height);

        //clamp x and y position to prevent object from dragging outside canvas
        posX = mouseX - dragHoldX;
        posX = (posX < minX) ? minX : ((posX > maxX) ? maxX : posX);
        posY = mouseY - dragHoldY;      
        posY = (posY < minY) ? minY : ((posY > maxY) ? maxY : posY);

        shapes[dragIndex].x = posX;
        shapes[dragIndex].y = posY;

        drawScreen();       
    }

    function hitTest(shape, mx, my)
    {
        var dx = mx - shape.x;
        var dy = my - shape.y;

        return(dx * dx + dy * dy < shape.rad * shape.rad);
    }

    //drawing both shape (line and circle) and screen

    function drawScreen()
    {
        myContext.fillStyle = "#ffffff";
        myContext.fillRect(0, 0, myCanvas.width, myCanvas.height);
        drawShapes();
    }

    function drawShapes()
    {

        //line
        for(var i = 1; i < numShapes; i++)
        {
            myContext.beginPath();
            myContext.moveTo(shapes[0].x, shapes[0].y);
            myContext.lineTo(shapes[i].x, shapes[i].y);
            myContext.stroke();
        }

        //circle        
        for(var i = 0; i < numShapes; i++)
        {
            myContext.fillStyle = shapes[i].color;
            myContext.beginPath();
            myContext.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2*Math.PI, false);
            myContext.closePath();
            myContext.fill();
        }       
    }

</script>
</body>
</html>
Vineet
  • 93
  • 1
  • 2
  • 9
  • The events and callbacks are correctly fired, what you need is thinking the logic of what you want to do : On a mouse click and drag, you want your shape to follow the mouse. On a mouse Up, you want to restore the shape to its previous location ? If so, you need to store the shape's previous position. – Bathz Mar 06 '16 at 13:44

1 Answers1

2

Here's one way to move a circle away from its origin and animate it back

Move a circle (drag or programmatically) away from its original position

Listen for mouse events:

  • On mousedown, test if the mouse was downed inside the circle. If yes, save the mouse position and set a flag indicating a drag operation has begun.

  • On mousemove, calculate the distance the mouse has moved since the last mousemove event and move the circle by that distance.

  • On mouseup (or mouseout), clear the isDragging flag, start an animation loop to animate the circle back to its original position, and set a flag indicating an animation has begun.

To animate a circle back to its original position

Create an animation loop using requestAnimationFrame.

  • Calculate how long the animation has been running (==elapsed time).

  • The circle will be animated from its dragDrop position back to its original position. Calculate the current circle position based on elapsed time. You can use one of Robert Penner's Easing functions to add easing effects to the animation.

  • Clear the canvas and redraw the circle in its currently rebounding position

  • If the animation is complete (==circle is back to its origin) then clear the isAnimating flag. Otherwise, request another animation frame if the animation is not yet complete.

Here's a annotated example code and a Demo:

// canvas vars
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
    var BB=canvas.getBoundingClientRect();
    offsetX=BB.left;
    offsetY=BB.top;        
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }

// drag vars
var isDown=false;
var startX,startY;

// animation vars
var originalX=50;
var originalY=50;
var radius=30;
var stretchedX=originalX;
var stretchedY=originalY;
var duration=1000;
var startTime=0;
var isAnimating=false;

// set canvas styles
ctx.fillStyle='skyblue';
ctx.strokeStyle='lightgray';
ctx.lineWidth=3;

// listen for mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUpOut(e);});
$("#canvas").mouseout(function(e){handleMouseUpOut(e);});

draw(originalX,originalY);

function animate(time){
    // not animating, just return
    if(!isAnimating){return;}
    
    // calc how long the animation has been running
    var elapsed=time-startTime;
    if(elapsed>duration){ elapsed=duration; }
    
    // calc the current x,y using easing
    var x=easeOutBounce(elapsed,stretchedX,originalX-stretchedX,duration);
    var y=easeOutBounce(elapsed,stretchedY,originalY-stretchedY,duration);

    // draw the scene
    ctx.clearRect(0,0,cw,ch);
    draw(x,y);

    // if the animation isn't done, request a new frame
    if(isAnimating && elapsed>=duration){
        // done, turn off animation
        isAnimating=false;            
    }else{
        // more animating to be done
        requestAnimationFrame(animate);
    }

}

function draw(x,y){
    // draw small circle in original position
    // draw larger circle in dragged position
    // connect 2 circles with line
    ctx.beginPath();
    ctx.moveTo(originalX,originalY);
    ctx.lineTo(x,y);
    ctx.moveTo(originalX,originalY);
    ctx.arc(originalX,originalY,5,0,Math.PI*2);
    ctx.moveTo(x,y);
    ctx.arc(x,y,radius,0,Math.PI*2);
    ctx.closePath();
    ctx.stroke();
    ctx.fill();
}


function handleMouseDown(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();
  
  startX=parseInt(e.clientX-offsetX);
  startY=parseInt(e.clientY-offsetY);

  // if the mouse is down in the circle
  // start dragging
  var dx=startX-originalX;
  var dy=startY-originalY;
  if(dx*dx+dy*dy<radius*radius){
      isAnimating=false;
      isDown=true; 
  }
}

function handleMouseUpOut(e){
  if(!isDown){return;}         

  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();
  
  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // stop dragging, start animating
  isDown=false;
  stretchedX=mouseX;
  stretchedY=mouseY;
  isAnimating=true;
  startTime=performance.now();
  requestAnimationFrame(animate);
}

function handleMouseMove(e){
  if(!isDown){return;}

  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // calc distance mouse has moved since last mousemove event
  var dx=mouseX-startX;
  var dy=mouseY-startY;
  startX=mouseX;
  startY=mouseY;

  // draw the scene
  ctx.clearRect(0,0,cw,ch);
  draw(mouseX,mouseY);
  
}

// easing functions 
// Thank you Robert Penner: http://robertpenner.com/easing/
function easeInBounce(t, b, c, d){
  return c - easeOutBounce(d-t, 0, c, d) + b;
}
function easeOutBounce(t, b, c, d){
  if ((t/=d) < (1/2.75)) {
    return c*(7.5625*t*t) + b;
  } else if (t < (2/2.75)) {
    return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
  } else if (t < (2.5/2.75)) {
    return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
  } else {
    return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
  }
}
function easeInOutBounce(t, b, c, d){
  if (t < d/2) return easeInBounce(t*2, 0, c, d) * .5 + b;
  return easeOutBounce(t*2-d, 0, c, d) * .5 + c*.5 + b;
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Drag circle. Circle returns to origin with easing.</h4>
<canvas id="canvas" width=500 height=300></canvas>
markE
  • 102,905
  • 11
  • 164
  • 176
  • i am using canvas but having problem with my 2 rectangles get on to one another.this is 1 js bin i have created:http://output.jsbin.com/zacacufuxa – I Love Stackoverflow May 13 '16 at 05:52
  • 1
    @Learning I don't understand your comment. You should post a new question with more details so we can get a better understanding of what you're wanting to do. – markE May 14 '16 at 05:13
  • See i have posted this question:http://stackoverflow.com/questions/37208156/update-html-canvas-tag-on-every-ajax-request-with-new-data – I Love Stackoverflow May 14 '16 at 05:38