0

I made a small JS program that is supposed to simulate ball physics, where the HTML canvas is supposed to resize to the window height. I have made it so that the canvas resizes, but when it resizes the mouse position doesn't work right, and the balls don't appear on the screen when it is clicked (like they're supposed to). I've been using clientX & clientY to get the mouse position, but I don't know if that's the best method. Here is the code:

<!DOCTYPE <!DOCTYPE html>

<html>

<head>

 <style type="text/css">


  BODY {
            background: #00000;
  }

  #myCanvas {
   background-color: black;
  }



 </style>

 <title>Ball Simulator</title>

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>

 <script type="text/javascript">
  
 $(function() {
   c = document.getElementById('myCanvas');
   ctx = c.getContext("2d");
   objects = [];
   init()
   c.addEventListener("mousedown", onMouseDown);
   c.addEventListener("mouseup", onMouseUp);
   ctx.fillStyle = "#FFFFFF";
 });

 function resizeCanvas() {
   c.width = window.innerWidth;
   c.height = window.innerHeight;
 }

 function ball(x, y, radius, xVel, yVel) {
   this.x = x;
   this.y = y;
   this.radius = radius;
   this.xVel = xVel;
   this.yVel = yVel;
   this.direction = Math.random() * Math.PI * 2

   objects.push([x, y, radius, xVel, yVel, this.direction])
 };

 function stylusBall(x, y, radius) {

   ctx.beginPath();
   ctx.arc(x, y, radius, 0, 2 * Math.PI);
   ctx.fill();

 }

 function getDistance(x1, y1, x2, y2) {

   return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));

 };

 function getVerticalDistance(y1, y2) {
   return y2 - y1
 };

 function getAngle(x1, y1, x2, y2) {

   return Math.atan2(x2 - x1, y2 - y1);

 };

 function updateData() {
   ctx.clearRect(0, 0, 6000, 3100);
   for (i = 0; i < objects.length; i++) {
     var close = false
     var x = objects[i][0];
     var y = objects[i][1];
     var radius = objects[i][2];
     var xVel = objects[i][3];
     var yVel = objects[i][4];
     var dir = objects[i][5];

     for (n = 0; n < objects.length; n++) {

       if (n != i) {
        close = false
         var nX = objects[n][0];
         var nY = objects[n][1];
         var nRadius = objects[n][2];
         var nAngle = getAngle(x, y, nX, nY);

         var distance = getDistance(x, y, nX, nY);

         if (distance == (nRadius + radius) || distance < (nRadius + radius)) {

           var bounceForce = 1.5
           xVel = xVel * -1 + bounceForce * Math.cos(nAngle);
           yVel = yVel * -1 + bounceForce * Math.sin(nAngle);
           close = true

         };

       };

     }

     if (getVerticalDistance(y, window.innerHeight - 5 - radius) > 0 && !close) {
       yVel += 2;
     } else if (getVerticalDistance(y, window.innerHeight - 5 - radius) < 0) {
       yVel = yVel * -1;

       if (getVerticalDistance(y, window.innerHeight - 5 - radius) < -20) {
         y = y - 50
       }
     }

     yVel *= 0.97;
     xVel *= 0.99;

     objects[i][3] = xVel
     objects[i][4] = yVel

     objects[i][0] = x + xVel
     objects[i][1] = y + yVel

   };

//   window.requestAnimationFrame(updateData)

 };

 function drawArrow(x1, y1, x2, y2) {

 }

 function mouseMove(e) {
   mouseX = e.clientX;
   mouseY = e.clientY;
 }

 function onMouseDown() {
   createRadius = 5;

   anim = requestAnimationFrame(increase);
 };

 function increase() {
   if (createRadius < 80) {
     createRadius += 3;
   }
   newStylus = new stylusBall(mouseX, mouseY, createRadius)
   anim = requestAnimationFrame(increase);
 };

 function onMouseUp() {
   window.cancelAnimationFrame(anim);
   newBall = new ball(mouseX, mouseY, createRadius, 0, 0);
 };

 function render() {

   for (i = 0; i < objects.length; i++) {
     ctx.beginPath();

     ctx.arc(objects[i][0], objects[i][1], objects[i][2], 0, 2 * Math.PI);

     ctx.fill();
   };
//   window.requestAnimationFrame(render)
 };


 function loop() {
  c.width = window.innerWidth;
  c.height = window.innerHeight;
  updateData();
  render();
  window.requestAnimationFrame(loop);
 }

 function init() {
   loop();
 }
 </script>

</head>

  <body style="margin: 0;">

    <canvas id='myCanvas' onmousemove="mouseMove(event)">

  </body>

</html>
xpy
  • 5,481
  • 3
  • 29
  • 48
Owen M
  • 2,585
  • 3
  • 17
  • 38
  • You might be interested in trying this popular animation framework: [Phaser](http://phaser.io/). See the [ball](http://phaser.io/examples/v2/arcade-physics/multiball) example. – Yogi Mar 21 '16 at 22:49
  • 2
    First, format your code. It's difficult to read right now. Next, make the smallest, working example possible that shows your problem. Next, clientX and clientY should be working fine. What's going wrong exactly? – Mike Cluck Mar 21 '16 at 22:49
  • This has been answered here **http://stackoverflow.com/questions/3011418/onmousemove-get-mouse-position** – Arif Burhan Mar 21 '16 at 23:29
  • Check out this previous [Q&A](http://stackoverflow.com/questions/35926362/html5-canvas-distortion/35927232#35927232) that shows how to efficiently get the mouse position both when the user resizes and when the user scrolls. – markE Mar 22 '16 at 00:15

2 Answers2

1

I think this this what can help, you need to get the mouse position relative to the canvas. So creating a function to get the mouse position:

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}

Then when you are adding an event listener for both mousedown & mouseup events, you can set the mouse position:

canvas.addEventListener('mousedown', function(evt) {
    isMouseDown = true;
    mousePos = getMousePos(canvas, evt);
    message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
    writeMessage(canvas, message);

  }, false);
lili2311
  • 66
  • 5
  • This is an "ok" solution. It could be made more efficient because the bounding rectangle typically only changes on resizing and on scrolling. So you could save the `rect.left` and `rect.top` and reuse them (instead of recalculating them) in `getMousePos'. – markE Mar 22 '16 at 00:13
0

If you want to get the mouse position relative to the canvas top-left point, you should use event.offsetX and event.offsetY (given that you have attached the mousemove event handler to the canvas element).

Try this:

function mouseMove(e) {
      var mouseX = e.offsetX;
      var mouseY = e.offsetY;
}
gipouf
  • 1,221
  • 3
  • 15
  • 43