Main content
Computer programming - JavaScript and the web
A button function
If you went through the Intro to JS course, then you made a few simple buttons in the Logic challenges Your First Button and Smarter Button. In case you forgot, let's re-hash how to make a simple button.
First, what are the bare minimum features of a button?
- A shape on the canvas (typically a rectangle)
- Includes a label or icon that describes what it will do
- Responds to the user clicking on it (but not elsewhere)
We can achieve #1 and #2 pretty easily:
fill(0, 234, 255);
rect(100, 100, 150, 50, 5);
fill(0, 0, 0);
textSize(19);
text("Useless button", 110, 133);
To achieve #3, we need to define a
mouseClicked
function that will get called when the user clicks, and inside of that, we need to check whether mouseX
and mouseY
are within the bounding box of the button. For the button above, it spans from x=100 to x=250, and from y=100 to y=150, as illustrated below:We can check those coordinates by
&&
ing together four conditions:mouseClicked = function() {
if (mouseX >= 100 && mouseX <= 250 &&
mouseY >= 100 && mouseY <= 150) {
println("Still pretty useless");
}
};
Try clicking on it and off it below to verify that it works:
It definitely works, but it also worries me. I'm worried that it's not highly reusable code. How much work will I have to do if I want to change the position of the button? (Try it above!) I see a lot of "hard-coded" numbers in the code -- like the coordinates in the
mouseClicked
function, and I immediately start to wonder if there isn't a cleaner way.To start with, let's make variables of the position and size, so that we can change them in a single place and have the button clicking work still. I've added
btnX
, btnY
, btnWidth
and btnHeight
to the program below. Try changing their values around and clicking the button:Well, that's better. But still, how much work will I have to do if I want to add an extra button? Do I have to copy and paste all of that, and make
btn2X
, btn2Y
? Ugh, that doesn't sound fun at all. This sounds like good motivation to write a function that will take care of doing everything that's the same for buttons, and use parameters to take care of what's different. We could write it like this, turning the variables into parameters:var drawButton = function(btnX, btnY, btnWidth, btnHeight) {
fill(0, 234, 255);
rect(btnX, btnY, btnWidth, btnHeight, 5);
fill(0, 0, 0);
textSize(19);
textAlign(LEFT, TOP);
text("Useless button", btnX+10, btnY+btnHeight/4);
};
Then we'd call it like so:
drawButton(100, 100, 150, 50);
But, uh oh, what about our
mouseClicked
code? Do you see what the problem would be with it?mouseClicked = function() {
if (mouseX >= btnX && mouseX <= (btnX+btnWidth) &&
mouseY >= btnY && mouseY <= (btnY+btnHeight)) {
println("Still pretty useless");
}
};
If we had all this code together, we'd get an error from Oh Noes that "btnX is not defined" - and he's right! We turned
btnX
into a function parameter, which means it's no longer a global variable. That's great for re-usability of the drawButton
function, but now the mouseClicked
function has no way to know what coordinates to check.So we need to figure out a nice way to pass the information into
drawButton
and make that information available to mouseClicked
. I can think of a few options:- Re-introduce global variables for the position and size (
btnX, btnY, btnWidth, btnHeight
) - Introduce a global array that stores all the parameters (
var btn1 = [...];
) - Introduce a global object that stores the parameters (
var btn1 = {..}
) - Use object-oriented principles to define the button and store the properties (
var btn1 = new Button(...))
Which to choose? Well, I don't like the first one because we'll have to add so many global variables, and I have an allergy to global variables. I don't love the second technique because it's hard to read code that grabs data based on array indices. I like the third technique because it introduces only one global variable, and will produce more readable code. I also like the fourth technique, using object-oriented principles to create generic
Button
object types, but let's save that for later.We can create our global
btn1
object like so:var btn1 = {
x: 100,
y: 100,
width: 150,
height: 50
};
And change the
drawButton
function to accept a single object that it then grabs properties from:var drawButton = function(btn) {
fill(0, 234, 255);
rect(btn.x, btn.y, btn.width, btn.height, 5);
fill(0, 0, 0);
textSize(19);
textAlign(LEFT, TOP);
text("Useless button", btn.x+10, btn.y+btn.height/4);
};
The
mouseClicked
function will check the properties of the global variable:mouseClicked = function() {
if (mouseX >= btn1.x && mouseX <= (btn1.x+btn1.width) &&
mouseY >= btn1.y && mouseY <= (btn1.y+btn1.height)) {
println("Still pretty useless");
}
};
Try it out below! Like before, try changing different parameters of the button and seeing if everything still works:
The whole point of that was to enable us to easily add more buttons, the ultimate re-usability test. Can we do it? Ba Bum BUM.
We'll start with a new global variable,
btn2
, offset in the y direction from the first button:var btn2 = {
x: 100,
y: 200,
width: 150,
height: 50
};
Then we'll draw that button:
drawButton(btn2);
That will succeed in drawing 2 buttons on the canvas, but only the first will respond to clicks. We can make the second respond by duplicating the logic and swapping
btn2
for btn1
, like so:mouseClicked = function() {
if (mouseX >= btn1.x && mouseX <= (btn1.x+btn1.width) &&
mouseY >= btn1.y && mouseY <= (btn1.y+btn1.height)) {
println("Still pretty useless");
}
if (mouseX >= btn2.x && mouseX <= (btn2.x+btn2.width) &&
mouseY >= btn2.y && mouseY <= (btn2.y+btn2.height)) {
println("2nd one still quite useless!");
}
};
But doesn't all that repeated code just make your nose crinkle? Let's make a function
isMouseInside
that knows how to check any button object and return true if the mouse was inside it:var isMouseInside = function(btn) {
return (mouseX >= btn.x &&
mouseX <= (btn.x+btn.width) &&
mouseY >= btn.y &&
mouseY <= (btn.y+btn.height));
};
And now we can use that function inside
mouseClicked
to greatly reduce the amount of repetitive code:mouseClicked = function() {
if (isMouseInside(btn1)) {
println("Still pretty useless");
} else if (isMouseInside(btn2)) {
println("2nd one still quite useless!");
}
};
And there we have it! We've used functions to draw multiple buttons, and made it relatively easy to add new buttons. Try it out below:
We could keep going -- making arrays of all the buttons in a program, making it possible to customize the label and color of a button -- but hopefully this has given you a good basis in how to create simple buttons using functions. Next, we'll walk through how to create buttons using object-oriented principles.
Want to join the conversation?
- what if you wanted to do a circle, how would you make that a button??(147 votes)
- Draw the circle using the
ellipse()
function. Then check for the mouse being inside it with some code likeif (dist(circle.x, circle.y, mouseX, mouseY) < circle.radius) ...
.(263 votes)
- I am confused. At no point have we defined or said something about btn. The objects are either btn1 or btn2. How does btn work then?(73 votes)
- You did define it
var drawButton = function(btn) {
btn is a local variable that will equal any value entered when the function is called. WhendrawButton(btn1);
runs, btn is set to the value of "btn1". WhendrawButton(btn2);
runs, btn is then set to btn2.
If I were to adddrawButton(1);
, btn would be set to 1
Hope this helps :D(136 votes)
- somebody help ,i do not understand the isMouseInside function , what does return ?(32 votes)
isMouseInside()
returns a boolean value (true or false) telling you if the mouse is inside the button area.(66 votes)
- I noticed printLn was used many times. Is console.log in Java script the same thing as printLn in proccesing JS.(19 votes)
- Yeah, I'm pretty sure that's what it is, except println is ProcessingJS while console.log is for Javascript(10 votes)
- why do you use the 'mouseClicked' function to verify if the mouse is clicked instead of 'mouseIsPressed'? I use it all the time.(8 votes)
- 'mouseClicked' only calls the function if you press AND RELEASE the mouse. mousePressed, however, calls the function only when the mouse if pressed (not released). hope this helps! :)(8 votes)
- I'm interested to know how the corners of the rectangles were rounded by simply creating a rect(). Anyone got an idea?(8 votes)
rect()
typically has 4 parameters, but there is a fifth, which controls the corners.rect(100, 100, 50, 50, 4);
will give you rounded corners.(19 votes)
- It got a little confusing, maybe it would be easier to just make another button by copying and pasting the first code, then change the numerals for the position of the button. wouldn't that be easier?(13 votes)
- Putting it in variable form is helpful in other ways too. Like if you were going to do something like I tried to do in this program
https://www.khanacademy.org/computer-programming/simulator-of-changing-scenes/1699894652
And then wanted to copy the pictures from scene to scene and change their locations, do you see my problem? You can't really change it without making it REALLY MESSY. Learn how to do variables! It could have saved me a LOT of time, if I had.(13 votes)
- If you had a game and wanted to click on one of objects to make it disappear, how do you do that?(8 votes)
- There are many ways to do it, but one would be to store the objects (whatever they are in the specific context you're thinking of) inside an array, and to have a mouseClicked function splice the object that is being clicked on out of the array when you click (in effect deleting the object).(9 votes)
- Why cant' you just make videos i beg u all to do that(7 votes)
- I think you should make a video and post it with this request.(7 votes)
- I kinda understand how btn works (kinda) but i am confused, in the challenge, where it points out btn1.___();, i do not know how to figure this part out. I read this article and i skimmed through all the example parts and it does not show nor explain how to use this command when making a button. Please help. I am confused. :)(6 votes)