JavaScript Day 26: Mouse Part I

OK, here’s something we’ve largely passed by: handling mouse interactions. Might be useful, eh?

HTML5 has various options to capture mouse and other events, and various ways of determining mouse coordinates. These vary in support across various browsers and platforms, meaning it can get a bit complex coding this stuff up on your own. This is where a framework like jQuery comes in real handy. It abstracts the various browser differences and gives you a uniform way of coding this stuff that should work on just about anything. Others probably know better than me how well it actually fulfills that promise, but I’ve had decent luck with it so far.

Say we want to know when the mouse moves on the canvas. We use the jQuery mousemove function, passing in an event handling function like so:

[php lang=”JavaScript”]$(function () {
$(“#canvas”).mousemove(function (event) {
// do stuff when the mouse moves on the canvas
});
});[/php]

In our document ready function, we get look for any objects with the id of “canvas”, and listen for the mousemove event, calling the anonymous function passed in. This function will be called whenever the mouse moves on the canvas.

Now, you probably want to know the mouse coordinates at this point. These are attached to the event object passed in. Actually, there are a number of different coordinates attached. Namely, pageX/pageY, clientX/clientY, and offsetX/offsetY. The page and client coordinates won’t really help us, as they are in a more global coordinate system. We want the coords of the mouse in relation to the exact object that triggered the event – the canvas. This we can get with offsetX and offsetY. It turns out that even some of these are not supported on all browsers and systems. From what I now understand, pageX and pageY are abstracted for all browsers. Unfortunately, this means we have to subtract the canvas’s position from the page position of the mouse location. It’s a bit more wordy, but at least you don’t have to do any browser checking. This should work for all. Thus we can do some simple drawing like so:

[php lang=”JavaScript”]$(function () {
var canvas, context;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);

$(“#canvas”).mousemove(function (event) {
context.fillRect(event.pageX – canvas.offsetLeft – 1, event.pageY – canvas.offsetTop- 1, 2, 2);
});
});[/php]

This just draws a small rectangle wherever the mouse moves, looking like this:

Or see it live here.

Or, we can combine yesterday’s network code with this:

[php lang=”JavaScript”]$(function () {
var i, canvas, context, points = [];

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
context.strokeStyle = “rgba(0, 0, 0, 0.2)”;

$(“#canvas”).mousemove(function (event) {
var p0, p1, dx, dy, dist, max = 150;
p0 = {x:event.pageX – this.offsetLeft, y:event.pageY – this.offsetTop};
for(i = 0; i < points.length; i += 1) { p1 = points[i]; dx = p1.x - p0.x; dy = p1.y - p0.y; dist = Math.sqrt(dx * dx + dy * dy); console.log(dist); if(dist < max) { context.beginPath(); context.lineWidth = 1.0 - dist / max; context.moveTo(p0.x, p0.y); context.lineTo(p1.x, p1.y); context.stroke(); } } points.push(p0); }); });[/php] This is almost identical to yesterday's example, except that rather than create a random point on a setInterval, we create a point wherever the mouse is whenever it moves.

Try it live here. And yes, this will seriously kill your CPU if you move the mouse for too long.

This entry was posted in JavaScript. Bookmark the permalink.

5 Responses to JavaScript Day 26: Mouse Part I

  1. Jasper St. Pierre says:

    Again, the examples don’t work in Firefox…

    The first is because you didn’t specify a fill style, so the context errors out with: “An invalid or illegal string was specified”.

    For the second, the event’s offsetX/Y isn’t defined in Firefox… see http://bugs.jquery.com/ticket/8523 and http://www.bit-101.com/jscanvas/mar26-2.html.

    It looks like layerX and layerY do the same thing in Firefox, see: https://developer.mozilla.org/en/DOM/event.layerX

    So, p0 = {x:event.offsetX || event.layerX, y:event.offsetY || event.layerY};

  2. pavlicko says:

    I miss actionscript programming as well, but that code is still pretty tight considering it’s running in the browser. Still, there’s a certain fluidity from flash that I’m just not seeing from javascript and canvas yet…of course that could be because I need a new computer.

  3. Tuimasika says:

    Hello!

    I’m trying to adapt your code to a previous canvas painter of mine… If it’s okay with you, of course 🙂

    Adding stuff like colors, line-width, saving to server, combining pictures etc.

    Everything else up to (and beyond) this point is working fine. but i’m having trouble moving away from the jquery dependency for the ” mousemove” function…

    I would like to use a pure;
    “canvas.addEventListener(‘mousemove’, event, false);” -style javascript solution, instead of the current;
    “$(“#canvas”).mousemove(function (event)” but can’t seem to get the syntax right.

    Any help you could provide, would be most welcome.

    Kind Regards,
    Jussi

    BTW. awesome site and tutorials!

  4. Tuimasika says:

    Hullo!

    Was able to resolve the problem by adding;

    canvas.addEventListener(‘mousemove’, ev_mousemove, false);

    and

    function ev_mousemove (ev) {

    var p0, p1, dx, dy, dist, max = 25;

    if (ev.layerX || ev.layerX == 0) { // Firefox
    p0 = {x:ev.layerX, y:ev.layerY};
    } else if (ev.offsetX || ev.offsetX == 0) { // Opera
    p0 = {x:ev.offsetX, y:ev.offsetY};
    }

    Thank god it’s friday 🙂

Leave a Reply