In this example, we create a simple canvas in which we can paint in different colors, depending on what color is currently selected which mouse button is pressed. Our "paint" is a series of circles that are rendered whenever the mouse button is down and when the mouse is moved. The canvas must also be in focus.
We use callback functions to accept user mouse input and keyboard input.
The keyboard instructions are outlined in the
index.htmlfile below.
We also can determine which mouse button was pressed and draw different colors depending on which button was pressed:
We also use some basic customization properties for the canvas such as background, border, and borderBlur to customize the canvas appearance, and all of the drawing logic is inside our callback functions.
Our canvas has 2 layers. Layer 0 contains the drawing canvas, and layer 1 is for our cursor. We only want to clear layer 1 each frame so we can render the new cursor position, size, and color. We want layer 0 to remain static.
Anything we need to draw on the canvas must be a class that extends Drawable meaning that it must implement the draw(context) function. We define draw functions within both our Circle and Cursor classes to satisfy this requirement.
Follow these steps to create a new webpack project and install the graphico dependency to run this example.
# Create and open project folder
mkdir Simple_Paint_demo
cd Simple_Paint_demo
# Initialize project and install dependencies
npm init -y
npm pkg set type="module"
npm i graphico@1.1.0 webpack-cli
# Create source files
touch index.html
mkdir src
touch src/index.js
# Open new files
open index.html
open src/index.js
Copy and paste the following source code blocks into the newly created files.
<html>
<head>
<script type="text/javascript" src="dist/main.js" defer></script>
</head>
<body>
<div id="canvas"></div>
<ul>
<li>Use the left/right arrows to cycle through paint colors</li>
<li>Use the up/down arrows to change brush stroke size</li>
<li>Use the left/right/middle mouse buttons to paint different colors</li>
<li>Press <kbd>P</kbd> to take a screenshot</li>
<li>Press <kbd>O</kbd> to start or stop screen recording</li>
</ul>
</body>
</html>
import { Canvas } from 'graphico';
// Mouse button IDs (could possibly be different for your hardware)
const LCLICK = 0,
MCLICK = 1,
RCLICK = 2;
// The HSL color hue
let hue = 0;
// The paint brush radius
let radius = 3;
// Return the HSL color code
function hsl(h = 0, s = 100, l = 50) {
return `hsl(${h},${s}%,${l}%)`;
}
// Extends `Drawable` by implementing the `draw` function.
class Circle {
#color;
#x;
#y;
constructor(color = '', x = 0, y = 0) {
this.#color = color;
this.#x = x;
this.#y = y;
}
draw(ctx) {
// Call HTML canvas context rendering 2D functions here using the `ctx` object
ctx.fillStyle = this.#color;
ctx.beginPath();
ctx.arc(this.#x, this.#y, radius, 0, 2 * Math.PI);
ctx.fill();
}
}
class Cursor {
#x;
#y;
constructor() {
this.#x = 0;
this.#y = 0;
}
updatePos(x = 0, y = 0) {
this.#x = x;
this.#y = y;
}
draw(ctx) {
ctx.strokeStyle = hsl(hue);
ctx.lineWidth = radius / 3;
ctx.beginPath();
ctx.arc(this.#x, this.#y, radius + 1, 0, 2 * Math.PI);
ctx.stroke();
}
}
const myCursor = new Cursor();
const canvas = new Canvas({
// Append the canvas onto the <div id="canvas"> element
parent: document.getElementById('canvas'),
// Set the background and border colors on focus/unfocus
background: '#aabbcc',
border: 'black',
borderBlur: 'gray',
showMouse: false,
numLayers: 2,
// The following 2 functions are event listeners for mouse/keyboard input (when the canvas is selected)
mousemove(x, y) {
// Change paint color depending on which mouse button was pressed
// We could use the `mousedown(button)` event listener to record which
// mouse button is down in a global `mouseButtonDown` variable, instead
// of calling `isMouseButtonDown(button)` each time the mouse moves.
if (canvas.isMouseButtonDown(LCLICK)) {
canvas.draw(new Circle(hsl(hue), x, y)); // Draws on layer 0 automatically
} else if (canvas.isMouseButtonDown(MCLICK)) {
canvas.draw(new Circle(hsl(hue + 90), x, y));
} else if (canvas.isMouseButtonDown(RCLICK)) {
canvas.draw(new Circle(hsl(hue + 180), x, y));
}
canvas.clear(1);
myCursor.updatePos(x, y);
canvas.draw(myCursor, 1); // Draw on layer 1
},
keydown(key) {
switch (key) {
case ('arrowup'): {
// Increase the brush size
if (radius < 10) {
radius++;
}
break;
}
case ('arrowdown'): {
// Decrease the brush size
if (radius > 1) {
radius--;
}
break;
}
case ('arrowleft'): {
// Change color by -45deg
hue -= 45;
break;
}
case ('arrowright'): {
// Change color by 45deg
hue += 45;
break;
}
case ('p'): {
// Take and save a screenshot
canvas.screenshot();
break;
}
case ('o'): {
// Capture a screen recording
if (canvas.isRecording()) {
canvas.stopRecording();
} else {
canvas.startRecording();
}
break;
}
}
canvas.clear(1);
canvas.draw(myCursor, 1); // Draw on layer 1
}
});
In the base project directory Simple_Paint_demo/, run the following command. If changes are made in the source files, the demo will automatically be recompiled. Press CTRL+C to stop running.
npx webpack --mode development --watch
Open the index.html file in any web browser of your choice! You should see a page similar to the one below.