1
\$\begingroup\$

Here's a simple program I wrote to teach myself the basics of using a mouse for a potential HTML5/JavaScript game. The thing that tripped me up was event.clientX and event.clientY don't return the correct values as they stand. One has to get the offsets of the canvas object, which in turn may be a child object of other objects whose offsets need to be obtained...

I found this a bit counter intuitive. If anyone has more elegant solutions, I'd be interested to learn about them.

var canvas, context, ball_pos;

var BALL_RADIUS = 15;

function start() {
    'use strict';
    canvas = document.getElementById('c');
    context = canvas.getContext('2d');
    ball_pos = [canvas.width / 2, canvas.height / 2];
}

function draw() {
    'use strict';

    // draw background
    context.fillStyle = "rgb(248,248,248)"; // off white
    context.fillRect(0, 0, canvas.width, canvas.height);

    // draw ball
    context.strokeStyle = 'black';
    context.lineWidth = 1;
    context.fillStyle = 'red';
    context.beginPath();
    context.arc(ball_pos[0], ball_pos[1], BALL_RADIUS, 0, Math.PI * 2, true);
    context.closePath();
    context.fill();
    context.stroke();
}

function animate() {
    'use strict';
    window.requestAnimationFrame(animate);
    draw();
}

function click(evt) {
    'use strict';
    var offset = [0, 0],
        obj = canvas;
    while (obj.offsetParent !== null) {
        offset[0] += obj.offsetLeft;
        offset[1] += obj.offsetTop;
        obj = obj.offsetParent;
    }
    ball_pos[0] = evt.clientX - offset[0];
    ball_pos[1] = evt.clientY - offset[1];
}

// register event handlers
window.onclick = click;

start();
animate();
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <canvas id="c" width="600" height="400"></canvas>
</body>
</html>

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

You can get the bounding rectangle for a canvas. Consider:

function click(evt) {
    'use strict';
    var bound = canvas.getBoundingClientRect();
    ball_pos[0] = evt.clientX - bound.left;
    ball_pos[1] = evt.clientY - bound.top;
}

This should help you to avoid walking up the stack of objects to find the relative position.

See it working here:

var canvas, context, ball_pos;

var BALL_RADIUS = 15;

function start() {
    'use strict';
    canvas = document.getElementById('c');
    context = canvas.getContext('2d');
    ball_pos = [canvas.width / 2, canvas.height / 2];
}

function draw() {
    'use strict';

    // draw background
    context.fillStyle = "rgb(248,248,248)"; // off white
    context.fillRect(0, 0, canvas.width, canvas.height);

    // draw ball
    context.strokeStyle = 'black';
    context.lineWidth = 1;
    context.fillStyle = 'red';
    context.beginPath();
    context.arc(ball_pos[0], ball_pos[1], BALL_RADIUS, 0, Math.PI * 2, true);
    context.closePath();
    context.fill();
    context.stroke();
}

function animate() {
    'use strict';
    window.requestAnimationFrame(animate);
    draw();
}

function click(evt) {
    'use strict';
    var bound = canvas.getBoundingClientRect();
    ball_pos[0] = evt.clientX - bound.left;
    ball_pos[1] = evt.clientY - bound.top;
}

// register event handlers
window.onclick = click;

start();
animate();
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <canvas id="c" width="600" height="400"></canvas>
</body>
</html>

\$\endgroup\$
1
  • \$\begingroup\$ Thanks, that looks much simpler than looping to the root object. \$\endgroup\$
    – joeblog
    Dec 12, 2014 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.