JSFiddle - React, Tailwind, and code Playground
by Lazaro Contreras
HTML
<script src="https://cdn.tailwindcss.com"></script>
<div class="flex flex-col h-screen">
<header class="bg-blue-600 py-2">
<h1 class="text-white text-center text-2xl font-bold">Canvas Drawing</h1>
</header>
<main class="flex-grow flex justify-center items-center">
<div class="relative rounded-md border border-gray-300 shadow-lg overflow-hidden">
<canvas id="canvas" class="w-96 h-96 sm:w-128 sm:h-128"></canvas>
<div class="absolute top-0 left-0 p-2">
<input type="color" id="colorPicker" class="h-10 w-10 rounded-full border border-gray-300">
</div>
</div>
</main>
<footer class="bg-gray-100 py-2">
<div class="container mx-auto flex justify-between px-4">
<div class="flex items-center space-x-2">
<button class="shapeBtn active" data-shape="line">
<svg class="w-6 h-6 stroke-current text-gray-700" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
<button class="shapeBtn" data-shape="square">
<svg class="w-6 h-6 stroke-current text-gray-700" viewBox="0 0 24 24">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
</svg>
</button>
<button class="shapeBtn" data-shape="circle">
<svg class="w-6 h-6 stroke-current text-gray-700" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="9"></circle>
</svg>
</button>
</div>
<button id="clearBtn" class="bg-white hover:bg-gray-200 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow">
Clear
</button>
</div>
</footer>
</div>
CSS
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
body {
font-family: 'Inter', sans-serif;
}
input[type="color"]::-webkit-color-swatch {
border: none;
border-radius: 50%;
}
input[type="color"]::-webkit-color-swatch-wrapper {
padding: 0;
}
input[type="color"]::-moz-color-swatch {
border: none;
border-radius: 50%;
}
input[type="color"]::-moz-color-swatch-wrapper {
padding: 0;
}
@media screen and (min-width: 640px) {
canvas {
width: 128px;
height: 128px;
}
}
JavaScript
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const colorPicker = document.getElementById('colorPicker');
const shapeBtns = document.querySelectorAll('.shapeBtn');
const clearBtn = document.getElementById('clearBtn');
let startX, startY;
function draw(x, y) {
ctx.lineTo(x, y);
ctx.stroke();
}
function drawRect(x, y, width, height) {
ctx.fillRect(x, y, width, height);
}
function drawCircle(x, y, radius) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.fill();
}
function startDrawing(event) {
startX = event.clientX - canvas.offsetLeft;
startY = event.clientY - canvas.offsetTop;
ctx.beginPath();
ctx.moveTo(startX, startY);
canvas.addEventListener('mousemove', continueDrawing);
}
function continueDrawing(event) {
const currentX = event.clientX - canvas.offsetLeft;
const currentY = event.clientY - canvas.offsetTop;
draw(currentX, currentY);
}
function stopDrawing() {
canvas.removeEventListener('mousemove', continueDrawing);
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function changeColor(event) {
ctx.fillStyle = event.target.value;
ctx.strokeStyle = event.target.value;
}
function changeShape(event) {
const shape = event.target.dataset.shape;
if (shape === 'line') {
canvas.removeEventListener('mousedown', startDrawing);
canvas.removeEventListener('mouseup', stopDrawing);
canvas.removeEventListener('mouseout', stopDrawing);
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
} else if (shape === 'square') {
canvas.removeEventListener('mousedown', startDrawing);
canvas.removeEventListener('mouseup', stopDrawing);
canvas.removeEventListener('mouseout', stopDrawing);
canvas.addEventListener('mousedown', function(event) {
startX = event.clientX - canvas.offsetLeft;
startY = event.clientY...