Canvas Drawing

Free-drawing to canvas element with crayon brush effect.

by the_voder

HTML

<div id="canvas-wrapper">

  <!-- Canvas element. Drawing in here -->
  <canvas id="canvas"></canvas>

  <!-- Color selector. Style any way you line, but must input elements must all have name "colors" -->
  <div id="colors">
    <!-- Change background colors in inline CSS to anything you like -->
    <input type="radio" style="background:black" name="colors" />
    <input type="radio" style="background:rgb(200, 50, 50)" name="colors" />
    <input type="radio" style="background:#222" name="colors" />
    <input type="radio" style="background:rgb(50, 200, 50)" name="colors" />
    <input type="radio" style="background:#666" name="colors" />
    <input type="radio" style="background:rgb(50, 50, 200)" name="colors" />
    <input type="radio" style="background:#AAA" name="colors" />
    <input type="radio" style="background:rgb(200, 200, 50)" name="colors" />
    <input type="radio" style="background:white" name="colors" />
    <input type="radio" style="background:rgb(200, 50, 200)" name="colors" />
  </div>

  <!-- Clear/save buttons. IDs must not be changed, but can be styled any way you like with your own CSS -->
  <button id="btn-clear">Clear canvas</button>
  <button id="btn-save">Save Canvas</button>

  <figure>
    <!-- "Saved" canvas image will appear here. ID must not be changed, but image can be styled + placed anywhere you like -->
    <img src="" alt="" id="canvas-img" />
    <figcaption>Saved image</figcaption>
  </figure>

</div>

CSS

body {
  background-color: #bbb;
  margin: 20px;
}

#canvas-wrapper {
	position: relative;
	width: 80%;
	margin-left: 10%;
	padding: 0;
}

#canvas {
  width: 100%;
  aspect-ratio: 16/9; /* set height to ratio */
  background-image: linear-gradient(-135deg, white, #EEE);
}

#colors {
  position: relative;
  width: 100%;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
}

input[type="radio"] {
  -webkit-appearance: none;
  background: rgba(255, 255, 255, 0.3);
  height: 50px;
  padding: 0;
  flex-grow: 1;
  border-radius: 20%;
}

input[type="radio"]:hover {
  background: rgba(255, 255, 255, 0.5);
}

input[type="radio"]:active {
  opacity: 0.5;
}

input[type="radio"]:checked {
  outline: 1px solid #aaa;
  box-shadow: inset 0 0 0 1px #777;
}

#btn-clear {}
#btn-save {}

#canvas-img {
	width: 200px;
	height: auto;
	background-color: white;
}

JavaScript

/*
Based on:
https://codepen.io/bartaxyz/pen/DQpbNB
by Ondřej Bártas

I suggest keeping this script as a separate file, rather than adding it to your other script file, and only linking to it on the page on which it's required.

Pure JavaScript (see notes at end re. jQuery).

Known Issues:

1. Draw-position is offset if page resized.
*/

// Define variables

// Define Brush object
const Brush = {
  size: 10,
  density: 10,
  color: selectColor()
};

const canvasWrapper = document.getElementById("canvas-wrapper");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
var firstClick = 1;
var isMouseDown = false;
var scrollY = 0;

// Canvas size
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;

//////////////////////////////
// EVENT-LISTENERS ///////////
//////////////////////////////

// Canvas events
canvas.addEventListener("mouseup", drawFalse, false);
canvas.addEventListener("mousedown", drawTrue, false);
canvas.addEventListener("mouseout", drawFalse, false);
canvas.addEventListener("mousemove", draw, false);
canvas.addEventListener("click", function() {
  return false;
}, false);

/* window.addEventListener("scroll", function(){
    scrollY = window.scrollY;
}); */

// Set up touch events for mobile, etc
// https://bencentra.com/code/2014/12/05/html5-canvas-touch-events.html
canvas.addEventListener("touchstart", function(e) {
  mousePos = getTouchPos(canvas, e);
  var touch = e.touches[0];
  var mouseEvent = new MouseEvent("mousedown", {
    clientX: touch.clientX,
    clientY: touch.clientY
  });
  canvas.dispatchEvent(mouseEvent);
}, false);

canvas.addEventListener("touchend", function(e) {
  var mouseEvent = new MouseEvent("mouseup", {});
  canvas.dispatchEvent(mouseEvent);
}, false);

canvas.addEventListener("touchmove", function(e) {
  var touch = e.touches[0];
  var mouseEvent = new MouseEvent("mousemove", {
    clientX: touch.clientX,
    clientY: touch.clientY
  });
 ...