This was part of a complex drawing project, which is not relevant right now. The idea was to have a fully configurable canvas, where you could pick colours and sizes to write and draw anything.
I’m sure this has been done before, so I tried to keep my code to a minimum, while making sure the code has no dependencies and it’s modern and fast.
Here’s the HTML structure:
<div class="container">
<canvas width="800%" height="400px" id="art"></canvas>
<div id="buttons">
<a id="reset">Restart</a>
<div id="red" class="color"></div>
<div id="blue" class="color"></div>
<div id="green" class="color"></div>
<div id="purple" class="color"></div>
<div id="orange" class="color"></div>
<div id="black" class="color"></div>
<div id="white" class="color"></div>
<div id="default" class="color">1</div>
<div id="three" class="color">3</div>
<div id="five" class="color">5</div>
<div id="ten" class="color">10</div>
<div id="fifteen" class="color">15</div>
<div id="twenty" class="color">20</div>
<a id="downloadLnk" class="color" href="#" download="illustration.png">Export</a>
</div>
</div>
Here’s the CSS:
canvas {
border: 1px solid #cbcbcb;
background: #ecf0f1;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);
cursor: crosshair;
}
.container {
position: relative;
}
#buttons {
position: absolute;
top: 5px;
left: 10px;
}
#reset {
font-size: 24px;
margin: 10px 10px 0 10px;
float: left;
cursor: pointer;
color: #7f8c8d;
}
#downloadLnk {
margin: 10px 10px 0 10px;
color: #7f8c8d;
}
.color {
color: #7f8c8d;
width: 26px;
height: 26px;
line-height: 26px;
float: left;
margin: 10px 1px 0 0;
cursor: pointer;
text-align: center;
}
#red {
background-color: #e74c3c;
}
#blue {
background-color: #3498db;
}
#green {
background-color: #2ecc71;
}
#purple {
background-color: #9b59b6;
}
#orange {
background-color: #f39c12;
}
#black {
background-color: black;
}
#white {
background-color: white;
}
And here’s the JavaScript functionality:
const canvas = document.getElementById('art');
const ctx = canvas.getContext('2d');
function getMousePos(canvas, evt) {
let rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function mouseMove(evt) {
let mousePos = getMousePos(canvas, evt);
ctx.lineTo(mousePos.x, mousePos.y);
ctx.stroke();
}
canvas.addEventListener('mousedown', (evt) => {
let mousePos = getMousePos(canvas, evt);
ctx.beginPath();
ctx.moveTo(mousePos.x, mousePos.y);
evt.preventDefault();
canvas.addEventListener('mousemove', mouseMove, false);
});
canvas.addEventListener('mouseup', () => {
canvas.removeEventListener('mousemove', mouseMove, false);
}, false);
document.getElementById('reset').addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}, false);
const colors = ['red', 'blue', 'green', 'purple', 'orange', 'black', 'white'];
const size = [1, 3, 5, 10, 15, 20];
const sizeNames = ['default', 'three', 'five', 'ten', 'fifteen', 'twenty'];
function listener(i) {
document.getElementById(colors[i]).addEventListener('click', () => {
ctx.strokeStyle = colors[i];
}, false);
}
function fontSizes(i) {
document.getElementById(sizeNames[i]).addEventListener('click', () => {
ctx.lineWidth = size[i];
}, false);
}
for (let i = 0; i < colors.length; i++) {
listener(i);
}
for (let i = 0; i < size.length; i++) {
fontSizes(i);
}
document.getElementById('downloadLnk').addEventListener('click', () => {
let image = canvas.toDataURL("image/png");
this.href = image;
});
See a live demo here.
While I’m not particularly happy with the CSS and I know there’s room for improvement, the code is pretty fast and does the job. It’s also mobile compatible.