Monday, November 18, 2013

Canvas Clickable Regions - Demystified

Let's face it, canvas stuff is never terse and annoying. Creating buttons on a canvas is even harder. First you have to draw the button, change it's state, and other complicated things.

For instance, if the user pushes the mouse down on one clickable region, and drags it over to ANOTHER clickable region, the "click" event will still fire and (therefore) fire the second region's click event.

So what kinds of things do we actually need to figure this stuff out?

Well, for starters, let's demystify the mouse event positions.

//let's cache the event
var priorEvt;
function getMousePos(evt) {
//set and store..
priorEvt = evt = evt || priorEvt;
//get the bounding rectangle
var rect = canvas.getBoundingClientRect();
//lastly, return the x and y coordinates
if (evt)
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
return {
x: 0,
y: 0
};
}
view raw getMousePos.js hosted with ❤ by GitHub


This will give you a way to get the mouse location of any click event. So let's build our clickable region first.

function CanvasButton(img, x, y, width, height) {
//this function takes an "position" object passed by the canvas click events
//to the position function defined above
function onButton(pos) {
//it determines if the position is greater than x, less than the width
//and greater than y, less than the height
return (x <= pos.x && pos.x <= x + width) &&
(y <= pos.y && pos.y <= y + height);
}
}


Cache the canvas and draw an image...

var canvas = yourCanvasHere;
function CanvasButton(img, x, y, width, height) {
//this function takes an "event" object passed by the canvas click events
function onButton(pos) {
//it determines if the position is greater than x, less than the width
//and greater than y, less than the height
return (x <= pos.x && pos.x <= x + width) &&
(y <= pos.y && pos.y <= y + height);
}
//go ahead and replace this section with whatever you need to draw the image
if (Object.prototype.toString.call(img) === '[object String]')
img = document.getElementById(img);
var ctx = canvas.getContext("2d");
ctx.drawImage(img, x, y, width, height);
}
view raw canvas.js hosted with ❤ by GitHub


..and the only things that are missing are the click events...

var down = false;
canvas.addEventListener("mousedown", function (evt) { //event listener
down = onButton(getMousePos(evt));
});
//handle the document mouseup to reset the "down" variable every time.
document.addEventListener("mouseup", function (evt) {
if (onButton(getMousePos(evt)) && down) {
//we got a click!
}
});


and put it all together!

var priorEvt;
function getMousePos(evt) {
priorEvt = evt = evt || priorEvt;
var rect = canvas.getBoundingClientRect();
if (evt)
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
return {
x: 0,
y: 0
};
}
function CanvasButton(img, x, y, width, height) {
//this function takes an "event" object passed by the canvas click events
function onButton(pos) {
//it determines if the position is greater than x, less than the width
//and greater than y, less than the height
return (x <= pos.x && pos.x <= x + width) &&
(y <= pos.y && pos.y <= y + height);
}
//go ahead and replace this section with whatever you need to draw the image
if (Object.prototype.toString.call(img) === '[object String]')
img = document.getElementById(img);
var ctx = canvas.getContext("2d");
ctx.drawImage(img, x, y, width, height);
//draw region end
//the button isn't toggled by default
var down = false;
canvas.addEventListener("mousedown", function (evt) { //event listener
down = onButton(getMousePos(evt));
});
//handle the document mouseup to reset the "down" variable every time.
document.addEventListener("mouseup", function (evt) {
if (onButton(getMousePos(evt)) && down) {
//we got a click!
}
});
}
view raw CanvasButton.js hosted with ❤ by GitHub


The final product looks a bit like this, because you totally took the code and made it work for your project.. right? Get coding people!

In functional health,
Josh

No comments:

Post a Comment