├── LICENSE ├── README.md ├── example ├── example.html ├── lib │ ├── p5.clickable.js │ └── p5.min.js ├── logo.png └── sketch.js ├── images └── logo.png └── library ├── p5.clickable.js └── p5.clickable.min.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Martín del Río 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 | 5 | 6 |

7 | 8 | Welcome! This is **p5.clickable**, a [p5.js](http://p5js.org) library that lets you create and customize **buttons** and assign event-based behaviours to them. With **p5.clickable** you can create buttons and define what happens when the user *hovers over*, *clicks*, *releases* or *moves* the cursor *outside* of them. 9 | 10 | Can't wait? Check [this **live example**](https://lartu.github.io/p5.clickable/example/example.html) to see some of the things this library can do. Its source code is available in the [example](example) folder of this repository. 11 | 12 | >:warning: **Attention Contributors!** It seems that in one poorly checked pull request some of the newly contributes features were deleted. Sorry! I will add them again in the next release alongside all new features. 13 | 14 | ## :telescope: Code Example 15 | With **p5.clickable** you can get a button up and running with just a few lines of code. For example, to create a plain white button at (20, 20) that when pressed changes color and shows an alert message you do: 16 | 17 | ```javascript 18 | myButton = new Clickable(); //Create button 19 | myButton.locate(20, 20); //Position Button 20 | myButton.onPress = function(){ //When myButton is pressed 21 | this.color = "#AAAAFF"; //Change button color 22 | alert("Yay!"); //Show an alert message 23 | } 24 | ``` 25 | Easy as pie! 26 | 27 | ## :microscope: Documentation 28 | 29 | ### Including the p5.clickable Library 30 | 31 | To include the **p5.clickable** library into your p5.js project, copy the [p5.clickable.js](library/p5.clickable.js) file into 32 | your project directory and then add the line 33 | 34 | ```html 35 | 36 | ``` 37 | 38 | to the HTML file that includes your p5.js script **after** the line that imports the p5 library, but **before** all of your personal code or the line that imports your personal code. Check the [example project HTML file](p5.clickable/example/example.html) for more information. 39 | 40 | ### Creating a Clickable 41 | 42 | **p5.clickable** provides the `Clickable` class (a *Clickable* is just a button). To create a button just instantiate a new Clickable, like this: 43 | 44 | ```javascript 45 | myButton = new Clickable(); 46 | ``` 47 | 48 | The starting position of a Clickable defaults to (0, 0) and its size to (100, 50). 49 | 50 | ~~You can also create it at a different location:~~ 51 | 52 | >:warning: Sorry, this isn't working at the moment. It will be re-added in the next release. 53 | 54 | ```javascript 55 | myButton = new Clickable(200,300); 56 | ``` 57 | 58 | ### Displaying a Clickable 59 | 60 | To **display** a Clickable, you have to call its `draw` method inside the `draw` function of your p5.js script. 61 | 62 | ```javascript 63 | function draw(){ // This is the p5.js draw function. 64 | //... 65 | myButton.draw(); // <- Draw the 'myButton' Clickable 66 | //... 67 | } 68 | ``` 69 | 70 | This is very important! If you don't call this method your button will not be shown and it also **won't respond 71 | to any events**! 72 | 73 | ### Moving a Clickable 74 | 75 | To move a Clickable you can change its `x` and `y` properties. You can also use this properties to read the current 76 | location of a Clickable. 77 | 78 | ```javascript 79 | myButton.x = 100; 80 | myButton.y = 200; 81 | ``` 82 | 83 | You can also use the `locate` method to change the location of a Clickable. 84 | 85 | ```javascript 86 | myButton.locate(100, 200); 87 | ``` 88 | 89 | ### Resizing a Clickable 90 | 91 | To resize a Clickable you can modify its `width` and `height` properties. You can also use this properties to read the current size of a Clickable. 92 | 93 | ```javascript 94 | myButton.width = 250; 95 | myButton.height = 100; 96 | ``` 97 | 98 | You can also use the `resize` method to change the size of a Clickable. 99 | 100 | ```javascript 101 | myButton.resize(250, 100); 102 | ``` 103 | 104 | ### Altering the Appearance of a Clickable 105 | 106 | Clickables contain properties that can be changed to alter their appearance: 107 | 108 | ```javascript 109 | myButton.color = "#FFFFFF"; //Background color of the clickable (hex number as a string) 110 | myButton.cornerRadius = 10; //Corner radius of the clickable (float) 111 | myButton.strokeWeight = 2; //Stroke width of the clickable (float) 112 | myButton.stroke = "#000000"; //Border color of the clickable (hex number as a string) 113 | myButton.text = "Press Me"; //Text of the clickable (string) 114 | myButton.textColor = "#000000"; //Color of the text (hex number as a string) 115 | myButton.textSize = 12; //Size of the text (integer) 116 | myButton.textFont = "sans-serif"; //Font of the text (string) 117 | myButton.textScaled = false; //Whether to scale the text with the clickable (boolean) 118 | ``` 119 | 120 | ### Clickable Events 121 | 122 | The Clickable class provide four methods that are called when the user interacts with a Clickable: `onOutside`, `onHover`, `onPress` and `onRelease`. 123 | 124 | `onOutside` is called whenever the cursor is not hovering over the Clickable. 125 | 126 | ```javascript 127 | myButton.onOutside = function(){ 128 | console.log("Hey! Press me!"); 129 | } 130 | ``` 131 | 132 | `onHover` is called whenever the cursor is hovering over a Clickable, but it is not being pressed. 133 | 134 | ```javascript 135 | myButton.onHover = function(){ 136 | console.log("The cursor is over me!"); 137 | } 138 | ``` 139 | 140 | `onPress` is called when the user presses the Clickable. 141 | 142 | ```javascript 143 | myButton.onPress = function(){ 144 | console.log("I have been pressed!"); 145 | } 146 | ``` 147 | 148 | `onRelease` is called when the user clicks a Clickable and then releases the click while within the area of the Clickable. 149 | 150 | ```javascript 151 | myButton.onRelease = function(){ 152 | console.log("I have been released!"); 153 | } 154 | ``` 155 | 156 | ### Images in a Clickable 157 | 158 | You can add an image to a clickable like this: 159 | 160 | ```javascript 161 | myButton.image = myImage; // myImage is an image loaded from p5's loadImage() 162 | ``` 163 | 164 | By default the image will stretch to fill the button, but you can disable the stretching with the `fitImage` property. 165 | 166 | ```javascript 167 | myButton.fitImage = true; // fits the image inside the button with the image's original aspect ratio 168 | ``` 169 | 170 | You can also scale the image with the `imageScale` property. 171 | 172 | ```javascript 173 | myButton.imageScale = 1.2; // useful if your image has some extra transparent padding 174 | ``` 175 | 176 | ## :beers: Contributing 177 | If there's a missing feature you'd like to see on p5.clickable, feel free to write it and submit a pull request. Something broke? Please try to fix it! Also feel free to submit issues, bug reports and requests for future features. 178 | 179 | ## :scroll: Licensing 180 | The **p5.clickable** library is licensed under the MIT License. You can find a copy of the MIT License on this repository. 181 | 182 | This repository also includes code from the [p5.js](https://github.com/processing/p5.js) library, that is licensed under the LGPL 2.1 license. 183 | -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | p5.js example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example/lib/p5.clickable.js: -------------------------------------------------------------------------------- 1 | //Determines if the mouse was pressed on the previous frame 2 | var cl_mouseWasPressed = false; 3 | //Last hovered button 4 | var cl_lastHovered = null; 5 | //Last pressed button 6 | var cl_lastClicked = null; 7 | //All created buttons 8 | var cl_clickables = []; 9 | 10 | //This function is what makes the magic happen and should be ran after 11 | //each draw cycle. 12 | p5.prototype.runGUI = function () { 13 | for (i = 0; i < cl_clickables.length; ++i) { 14 | if (cl_lastHovered != cl_clickables[i]) 15 | cl_clickables[i].onOutside(); 16 | } 17 | if (cl_lastHovered != null) { 18 | if (cl_lastClicked != cl_lastHovered) { 19 | cl_lastHovered.onHover(); 20 | } 21 | } 22 | if (!cl_mouseWasPressed && cl_lastClicked != null) { 23 | cl_lastClicked.onPress(); 24 | } 25 | if (cl_mouseWasPressed && !mouseIsPressed && cl_lastClicked != null) { 26 | if (cl_lastClicked == cl_lastHovered) { 27 | cl_lastClicked.onRelease(); 28 | } 29 | cl_lastClicked = null; 30 | } 31 | cl_lastHovered = null; 32 | cl_mouseWasPressed = mouseIsPressed; 33 | } 34 | 35 | p5.prototype.registerMethod('post', p5.prototype.runGUI); 36 | 37 | //This function is used to get the bounding size of a 38 | //string of text for use in the 'textScaled' property 39 | function getTextBounds(m, font, size) { 40 | let txt = document.createElement("span"); 41 | document.body.appendChild(txt); 42 | 43 | txt.style.font = font; 44 | txt.style.fontSize = size + "px"; 45 | txt.style.height = 'auto'; 46 | txt.style.width = 'auto'; 47 | txt.style.position = 'absolute'; 48 | txt.style.whiteSpace = 'no-wrap'; 49 | txt.innerHTML = m; 50 | 51 | let width = Math.ceil(txt.clientWidth); 52 | let height = Math.ceil(txt.clientHeight); 53 | document.body.removeChild(txt); 54 | return [width, height]; 55 | } 56 | 57 | //Button Class 58 | function Clickable() { 59 | this.x = 0; //X position of the clickable 60 | this.y = 0; //Y position of the clickable 61 | this.width = 100; //Width of the clickable 62 | this.height = 50; //Height of the clickable 63 | this.color = "#FFFFFF"; //Background color of the clickable 64 | this.cornerRadius = 10; //Corner radius of the clickable 65 | this.strokeWeight = 2; //Stroke width of the clickable 66 | this.stroke = "#000000"; //Border color of the clickable 67 | this.text = "Press Me"; //Text of the clickable 68 | this.textColor = "#000000"; //Color for the text shown 69 | this.textSize = 12; //Size for the text shown 70 | this.textFont = "sans-serif"; //Font for the text shown 71 | this.textScaled = false; //Scale the text with the size of the clickable 72 | 73 | // image options 74 | this.image = null; // image object from p5loadimage() 75 | this.fitImage = false; // when true, image will stretch to fill button 76 | this.imageScale = 1.0; 77 | this.tint = null; // tint image using color 78 | this.noTint = true; // default to disable tinting 79 | this.filter = null; // filter effect 80 | 81 | this.updateTextSize = function () { 82 | if (this.textScaled) { 83 | for (let i = this.height; i > 0; i--) { 84 | if (getTextBounds(this.text, this.textFont, i)[0] <= this.width 85 | && getTextBounds(this.text, this.textFont, i)[1] <= this.height) { 86 | console.log("textbounds: " + getTextBounds(this.text, this.font, i)); 87 | console.log("boxsize: " + this.width + ", " + this.height); 88 | this.textSize = i / 2; 89 | break; 90 | } 91 | } 92 | } 93 | } 94 | this.updateTextSize(); 95 | 96 | this.onHover = function () { 97 | //This function is ran when the clickable is hovered but not 98 | //pressed. 99 | } 100 | 101 | this.onOutside = function () { 102 | //This function is ran when the clickable is NOT hovered. 103 | } 104 | 105 | this.onPress = function () { 106 | //This function is ran when the clickable is pressed. 107 | } 108 | 109 | this.onRelease = function () { 110 | //This function is ran when the cursor was pressed and then 111 | //released inside the clickable. If it was pressed inside and 112 | //then released outside this won't run. 113 | } 114 | 115 | this.locate = function (x, y) { 116 | this.x = x; 117 | this.y = y; 118 | } 119 | 120 | this.resize = function (w, h) { 121 | this.width = w; 122 | this.height = h; 123 | this.updateTextSize(); 124 | } 125 | 126 | this.drawImage = function(){ 127 | push(); 128 | imageMode(CENTER); 129 | let centerX = this.x + this.width / 2; 130 | let centerY = this.y + this.height / 2; 131 | let imgWidth = this.width; 132 | let imgHeight = this.height; 133 | if(this.fitImage){ 134 | let imageAspect = this.image.width / this.image.height; 135 | let buttonAspect = this.width / this.height; 136 | if(imageAspect > buttonAspect){ // image is wider than button 137 | imgWidth = this.width; 138 | imgHeight = this.height * (buttonAspect / imageAspect); 139 | } 140 | else{ 141 | imgWidth = this.width * (imageAspect / buttonAspect); 142 | imgHeight = this.height; 143 | } 144 | } 145 | 146 | image(this.image, centerX, centerY, imgWidth * this.imageScale, imgHeight * this.imageScale); 147 | 148 | if(this.tint && !this.noTint){ 149 | tint(this.tint) 150 | } else { 151 | noTint(); 152 | } 153 | if(this.filter){ 154 | filter(this.filter); 155 | } 156 | pop(); 157 | } 158 | 159 | this.draw = function () { 160 | push(); 161 | fill(this.color); 162 | stroke(this.stroke); 163 | strokeWeight(this.strokeWeight); 164 | rect(this.x, this.y, this.width, this.height, this.cornerRadius); 165 | fill(this.textColor); 166 | noStroke(); 167 | if(this.image){ 168 | this.drawImage(); 169 | } 170 | textAlign(CENTER, CENTER); 171 | textSize(this.textSize); 172 | textFont(this.textFont); 173 | text(this.text, this.x + this.width / 2, this.y + this.height / 2); 174 | if (mouseX >= this.x && mouseY >= this.y 175 | && mouseX < this.x + this.width && mouseY < this.y + this.height) { 176 | cl_lastHovered = this; 177 | if (mouseIsPressed && !cl_mouseWasPressed) 178 | cl_lastClicked = this; 179 | } 180 | pop(); 181 | } 182 | 183 | cl_clickables.push(this); 184 | } -------------------------------------------------------------------------------- /example/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lartu/p5.clickable/2ba6079ec79d6de7100f5141ed0cc1cfa7fc5121/example/logo.png -------------------------------------------------------------------------------- /example/sketch.js: -------------------------------------------------------------------------------- 1 | var canvas; 2 | var click1; 3 | var click2; 4 | var click3; 5 | var clickImg; 6 | 7 | function preload(){ 8 | clickImg = loadImage('./logo.png'); 9 | } 10 | function setup() { 11 | createCanvas(400, 400); 12 | 13 | //Create, style and resize clickables. 14 | click1 = new Clickable(); 15 | click1.locate(20, 20); 16 | //This function is ran when the clickable is hovered but not pressed. 17 | click1.onHover = function () { 18 | this.color = "#AAAAFF"; 19 | this.textColor = "#FFFFFF"; 20 | this.text = "Yay!"; 21 | } 22 | //This function is ran when the clickable is NOT hovered. 23 | click1.onOutside = function () { 24 | this.color = "#EEEEEE"; 25 | this.text = "Hello there!"; 26 | this.textColor = "#000000"; 27 | } 28 | //This function is ran when the clickable is pressed. 29 | click1.onPress = function () { 30 | this.stroke = "#FF0000"; 31 | } 32 | //This funcion is ran when the cursor was pressed and then 33 | //rleased inside the clickable. If it was pressed inside and 34 | //then released outside this won't work. 35 | click1.onRelease = function () { 36 | this.x += 50; 37 | } 38 | 39 | click2 = new Clickable(); 40 | click2.cornerRadius = 0; 41 | click2.textScaled = true; 42 | click2.text = "hello"; 43 | click2.locate(60, 60); 44 | click2.resize(250, 100); 45 | click2.onOutside = function () { 46 | this.color = "#FFFFFF"; 47 | } 48 | click2.onHover = function () { 49 | this.color = "#AA33AA"; 50 | } 51 | click2.onPress = function () { 52 | alert("Hi there!"); 53 | } 54 | 55 | click3 = new Clickable(); 56 | click3.image = clickImg; 57 | click3.locate(280,250); 58 | click3.resize(100,100); 59 | click3.text = ""; 60 | click3.onHover = function () { 61 | this.color = "#AA33AA"; 62 | this.noTint = false; 63 | this.tint = "#FF0000"; 64 | } 65 | click3.onOutside = function () { 66 | this.color = "#FFFFFF"; 67 | this.noTint = true; 68 | } 69 | 70 | // image will stretch to fill button by default 71 | click4 = new Clickable(); 72 | click4.image = clickImg; 73 | click4.imageScale = 1; 74 | click4.text = ""; 75 | click4.locate(10, 200); 76 | click4.resize(120, 90); 77 | click4.onHover = function () { 78 | click4.imageScale = 1.1; 79 | } 80 | click4.onOutside = function () { 81 | click4.imageScale = 1; 82 | } 83 | 84 | // centered and fitted 85 | click5 = new Clickable(); 86 | click5.image = clickImg; 87 | click5.fitImage = true; // no stretching! 88 | click5.imageScale = 1; 89 | click5.text = ""; 90 | click5.locate(140, 200); 91 | click5.resize(120, 90); 92 | click5.onHover = function () { 93 | click5.imageScale = 1.1; 94 | } 95 | click5.onOutside = function () { 96 | click5.imageScale = 1; 97 | } 98 | } 99 | 100 | function draw() { 101 | background(255); 102 | click1.draw(); 103 | click2.draw(); 104 | click3.draw(); 105 | click4.draw(); 106 | click5.draw(); 107 | } 108 | -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lartu/p5.clickable/2ba6079ec79d6de7100f5141ed0cc1cfa7fc5121/images/logo.png -------------------------------------------------------------------------------- /library/p5.clickable.js: -------------------------------------------------------------------------------- 1 | //Determines if the mouse was pressed on the previous frame 2 | var cl_mouseWasPressed = false; 3 | //Last hovered button 4 | var cl_lastHovered = null; 5 | //Last pressed button 6 | var cl_lastClicked = null; 7 | //All created buttons 8 | var cl_clickables = []; 9 | 10 | //This function is what makes the magic happen and should be ran after 11 | //each draw cycle. 12 | p5.prototype.runGUI = function () { 13 | for (i = 0; i < cl_clickables.length; ++i) { 14 | if (cl_lastHovered != cl_clickables[i]) 15 | cl_clickables[i].onOutside(); 16 | } 17 | if (cl_lastHovered != null) { 18 | if (cl_lastClicked != cl_lastHovered) { 19 | cl_lastHovered.onHover(); 20 | } 21 | } 22 | if (!cl_mouseWasPressed && cl_lastClicked != null) { 23 | cl_lastClicked.onPress(); 24 | } 25 | if (cl_mouseWasPressed && !mouseIsPressed && cl_lastClicked != null) { 26 | if (cl_lastClicked == cl_lastHovered) { 27 | cl_lastClicked.onRelease(); 28 | } 29 | cl_lastClicked = null; 30 | } 31 | cl_lastHovered = null; 32 | cl_mouseWasPressed = mouseIsPressed; 33 | } 34 | 35 | p5.prototype.registerMethod('post', p5.prototype.runGUI); 36 | 37 | //This function is used to get the bounding size of a 38 | //string of text for use in the 'textScaled' property 39 | function getTextBounds(m, font, size) { 40 | let txt = document.createElement("span"); 41 | document.body.appendChild(txt); 42 | 43 | txt.style.font = font; 44 | txt.style.fontSize = size + "px"; 45 | txt.style.height = 'auto'; 46 | txt.style.width = 'auto'; 47 | txt.style.position = 'absolute'; 48 | txt.style.whiteSpace = 'no-wrap'; 49 | txt.innerHTML = m; 50 | 51 | let width = Math.ceil(txt.clientWidth); 52 | let height = Math.ceil(txt.clientHeight); 53 | document.body.removeChild(txt); 54 | return [width, height]; 55 | } 56 | 57 | //Button Class 58 | function Clickable(x,y) { 59 | this.x = x; //X position of the clickable 60 | this.y = y; //Y position of the clickable 61 | this.width = 100; //Width of the clickable 62 | this.height = 50; //Height of the clickable 63 | this.color = "#FFFFFF"; //Background color of the clickable 64 | this.cornerRadius = 10; //Corner radius of the clickable 65 | this.strokeWeight = 2; //Stroke width of the clickable 66 | this.stroke = "#000000"; //Border color of the clickable 67 | this.text = "Press Me"; //Text of the clickable 68 | this.textColor = "#000000"; //Color for the text shown 69 | this.textSize = 12; //Size for the text shown 70 | this.textFont = "sans-serif"; //Font for the text shown 71 | this.textScaled = false; //Scale the text with the size of the clickable 72 | 73 | // image options 74 | this.image = null; // image object from p5loadimage() 75 | this.fitImage = false; // when true, image will stretch to fill button 76 | this.imageScale = 1.0; 77 | this.tint = null; // tint image using color 78 | this.noTint = true; // default to disable tinting 79 | this.filter = null; // filter effect 80 | 81 | this.updateTextSize = function () { 82 | if (this.textScaled) { 83 | for (let i = this.height; i > 0; i--) { 84 | if (getTextBounds(this.text, this.textFont, i)[0] <= this.width 85 | && getTextBounds(this.text, this.textFont, i)[1] <= this.height) { 86 | console.log("textbounds: " + getTextBounds(this.text, this.font, i)); 87 | console.log("boxsize: " + this.width + ", " + this.height); 88 | this.textSize = i / 2; 89 | break; 90 | } 91 | } 92 | } 93 | } 94 | this.updateTextSize(); 95 | 96 | this.onHover = function () { 97 | //This function is ran when the clickable is hovered but not 98 | //pressed. 99 | } 100 | 101 | this.onOutside = function () { 102 | //This function is ran when the clickable is NOT hovered. 103 | } 104 | 105 | this.onPress = function () { 106 | //This function is ran when the clickable is pressed. 107 | } 108 | 109 | this.onRelease = function () { 110 | //This function is ran when the cursor was pressed and then 111 | //released inside the clickable. If it was pressed inside and 112 | //then released outside this won't run. 113 | } 114 | 115 | this.locate = function (x, y) { 116 | this.x = x; 117 | this.y = y; 118 | } 119 | 120 | this.resize = function (w, h) { 121 | this.width = w; 122 | this.height = h; 123 | this.updateTextSize(); 124 | } 125 | 126 | this.drawImage = function(){ 127 | push(); 128 | imageMode(CENTER); 129 | let centerX = this.x + this.width / 2; 130 | let centerY = this.y + this.height / 2; 131 | let imgWidth = this.width; 132 | let imgHeight = this.height; 133 | if(this.fitImage){ 134 | let imageAspect = this.image.width / this.image.height; 135 | let buttonAspect = this.width / this.height; 136 | if(imageAspect > buttonAspect){ // image is wider than button 137 | imgWidth = this.width; 138 | imgHeight = this.height * (buttonAspect / imageAspect); 139 | } 140 | else{ 141 | imgWidth = this.width * (imageAspect / buttonAspect); 142 | imgHeight = this.height; 143 | } 144 | } 145 | 146 | image(this.image, centerX, centerY, imgWidth * this.imageScale, imgHeight * this.imageScale); 147 | 148 | if(this.tint && !this.noTint){ 149 | tint(this.tint) 150 | } else { 151 | noTint(); 152 | } 153 | if(this.filter){ 154 | filter(this.filter); 155 | } 156 | pop(); 157 | } 158 | 159 | this.draw = function () { 160 | push(); 161 | fill(this.color); 162 | stroke(this.stroke); 163 | strokeWeight(this.strokeWeight); 164 | rect(this.x, this.y, this.width, this.height, this.cornerRadius); 165 | fill(this.textColor); 166 | noStroke(); 167 | if(this.image){ 168 | this.drawImage(); 169 | } 170 | textAlign(CENTER, CENTER); 171 | textSize(this.textSize); 172 | textFont(this.textFont); 173 | text(this.text, this.x + this.width / 2, this.y + this.height / 2); 174 | if (mouseX >= this.x && mouseY >= this.y 175 | && mouseX < this.x + this.width && mouseY < this.y + this.height) { 176 | cl_lastHovered = this; 177 | if (mouseIsPressed && !cl_mouseWasPressed) 178 | cl_lastClicked = this; 179 | } 180 | pop(); 181 | } 182 | 183 | cl_clickables.push(this); 184 | } 185 | -------------------------------------------------------------------------------- /library/p5.clickable.min.js: -------------------------------------------------------------------------------- 1 | var cl_mouseWasPressed=!1,cl_lastHovered=null,cl_lastClicked=null,cl_clickables=[];function getTextBounds(t,i,e){let s=document.createElement("span");document.body.appendChild(s),s.style.font=i,s.style.fontSize=e+"px",s.style.height="auto",s.style.width="auto",s.style.position="absolute",s.style.whiteSpace="no-wrap",s.innerHTML=t;let h=Math.ceil(s.clientWidth),l=Math.ceil(s.clientHeight);return document.body.removeChild(s),[h,l]}function Clickable(){this.x=0,this.y=0,this.width=100,this.height=50,this.color="#FFFFFF",this.cornerRadius=10,this.strokeWeight=2,this.stroke="#000000",this.text="Press Me",this.textColor="#000000",this.textSize=12,this.textFont="sans-serif",this.textScaled=!1,this.image=null,this.fitImage=!1,this.imageScale=1,this.tint=null,this.noTint=!0,this.filter=null,this.updateTextSize=function(){if(this.textScaled)for(let t=this.height;t>0;t--)if(getTextBounds(this.text,this.textFont,t)[0]<=this.width&&getTextBounds(this.text,this.textFont,t)[1]<=this.height){console.log("textbounds: "+getTextBounds(this.text,this.font,t)),console.log("boxsize: "+this.width+", "+this.height),this.textSize=t/2;break}},this.updateTextSize(),this.onHover=function(){},this.onOutside=function(){},this.onPress=function(){},this.onRelease=function(){},this.locate=function(t,i){this.x=t,this.y=i},this.resize=function(t,i){this.width=t,this.height=i,this.updateTextSize()},this.drawImage=function(){push(),imageMode(CENTER);let t=this.x+this.width/2,i=this.y+this.height/2,e=this.width,s=this.height;if(this.fitImage){let t=this.image.width/this.image.height,i=this.width/this.height;t>i?(e=this.width,s=this.height*(i/t)):(e=this.width*(t/i),s=this.height)}image(this.image,t,i,e*this.imageScale,s*this.imageScale),this.tint&&!this.noTint?tint(this.tint):noTint(),this.filter&&filter(this.filter),pop()},this.draw=function(){push(),fill(this.color),stroke(this.stroke),strokeWeight(this.strokeWeight),rect(this.x,this.y,this.width,this.height,this.cornerRadius),fill(this.textColor),noStroke(),this.image&&this.drawImage(),textAlign(CENTER,CENTER),textSize(this.textSize),textFont(this.textFont),text(this.text,this.x+this.width/2,this.y+this.height/2),mouseX>=this.x&&mouseY>=this.y&&mouseX