Created
April 6, 2024 14:26
-
-
Save KutsuyaYuki/97fb3e978fbc1ea6b012e0ea17dbffa3 to your computer and use it in GitHub Desktop.
Paint-like drawing component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body | |
class="bg-white dark:bg-zinc-900 text-zinc-800 dark:text-zinc-200 min-h-screen flex flex-col items-center justify-center" | |
> | |
<div class="max-w-lg mx-auto p-6 space-y-6 bg-white dark:bg-zinc-800 rounded-lg shadow-lg"> | |
<div class="flex justify-center space-x-4"> | |
<button | |
id="pencil" | |
class="tool-btn bg-zinc-200 dark:bg-zinc-700 hover:bg-zinc-300 dark:hover:bg-zinc-600 p-3 rounded-full shadow-md transition duration-150 ease-in-out" | |
> | |
Pencil | |
</button> | |
<button | |
id="paintBucket" | |
class="tool-btn bg-zinc-200 dark:bg-zinc-700 hover:bg-zinc-300 dark:hover:bg-zinc-600 p-3 rounded-full shadow-md transition duration-150 ease-in-out" | |
> | |
Paint Bucket | |
</button> | |
<button | |
id="line" | |
class="tool-btn bg-zinc-200 dark:bg-zinc-700 hover:bg-zinc-300 dark:hover:bg-zinc-600 p-3 rounded-full shadow-md transition duration-150 ease-in-out" | |
> | |
Line | |
</button> | |
</div> | |
<div class="grid grid-cols-8 gap-2 justify-center"> | |
<div id="colorBlack" class="color-btn w-8 h-8 bg-black rounded-full cursor-pointer"></div> | |
<div id="colorRed" class="color-btn w-8 h-8 bg-red-500 rounded-full cursor-pointer"></div> | |
<div | |
id="colorYellow" | |
class="color-btn w-8 h-8 bg-yellow-500 rounded-full cursor-pointer" | |
></div> | |
<div id="colorGreen" class="color-btn w-8 h-8 bg-green-500 rounded-full cursor-pointer"></div> | |
<div id="colorBlue" class="color-btn w-8 h-8 bg-blue-500 rounded-full cursor-pointer"></div> | |
<div | |
id="colorIndigo" | |
class="color-btn w-8 h-8 bg-indigo-500 rounded-full cursor-pointer" | |
></div> | |
<div | |
id="colorPurple" | |
class="color-btn w-8 h-8 bg-purple-500 rounded-full cursor-pointer" | |
></div> | |
<input | |
type="color" | |
id="customColor" | |
class="w-8 h-8 rounded-full cursor-pointer border-none appearance-none" | |
/> | |
</div> | |
<div class="relative resize" style="resize: both; overflow: hidden;"> | |
<canvas | |
id="drawingArea" | |
class="w-full h-full border-4 border-zinc-300 dark:border-zinc-600 shadow-xl" | |
></canvas> | |
</div> | |
<div class="flex justify-center space-x-4 mt-4"> | |
<button id="clearCanvas" class="bg-red-500 hover:bg-red-600 text-white p-2 rounded-md"> | |
Clear | |
</button> | |
<button id="download" class="bg-green-500 hover:bg-green-600 text-white p-2 rounded-md"> | |
Download | |
</button> | |
</div> | |
</div> | |
<script> | |
let currentTool = 'pencil'; | |
let currentColor = '#000000'; | |
const canvas = document.getElementById('drawingArea'); | |
const ctx = canvas.getContext('2d'); | |
let isDrawing = false; | |
// Initialize canvas size | |
resizeCanvas(); | |
canvas.addEventListener('mousedown', startDrawing); | |
canvas.addEventListener('mousemove', draw); | |
canvas.addEventListener('mouseup', stopDrawing); | |
canvas.addEventListener('mouseout', stopDrawing); | |
document.querySelectorAll('.tool-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
setCurrentTool(this.id); | |
document.querySelectorAll('.tool-btn').forEach(btn => btn.classList.remove('outline')); | |
this.classList.add('outline', 'outline-2', 'outline-offset-2', 'outline-blue-500'); | |
}); | |
}); | |
document.getElementById('clearCanvas').addEventListener('click', clearCanvas); | |
document.getElementById('download').addEventListener('click', downloadCanvas); | |
document.querySelectorAll('.color-btn, #customColor').forEach(item => { | |
item.addEventListener('click', selectColor); | |
}); | |
function startDrawing(e) { | |
isDrawing = true; | |
ctx.beginPath(); | |
ctx.moveTo(e.offsetX, e.offsetY); | |
} | |
function draw(e) { | |
if (!isDrawing) return; | |
if (currentTool === 'pencil' || currentTool === 'line') { | |
ctx.lineTo(e.offsetX, e.offsetY); | |
ctx.strokeStyle = currentColor; | |
ctx.stroke(); | |
} | |
} | |
function stopDrawing() { | |
isDrawing = false; | |
} | |
function selectColor(e) { | |
document.querySelectorAll('.color-btn').forEach(btn => btn.classList.remove('ring', 'ring-offset-2', 'ring-blue-500')); | |
if (e.target.id === 'customColor') { | |
currentColor = e.target.value; | |
} else { | |
currentColor = window.getComputedStyle(e.target).backgroundColor; | |
e.target.classList.add('ring', 'ring-offset-2', 'ring-blue-500'); | |
} | |
} | |
function setCurrentTool(tool) { | |
currentTool = tool; | |
} | |
function clearCanvas() { | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
} | |
function downloadCanvas() { | |
const image = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); | |
const link = document.createElement('a'); | |
link.download = 'my-drawing.png'; | |
link.href = image; | |
link.click(); | |
} | |
// Adjust canvas size without scaling the content | |
function resizeCanvas() { | |
const rect = canvas.parentElement.getBoundingClientRect(); | |
canvas.width = rect.width; | |
canvas.height = rect.height; | |
} | |
window.addEventListener('resize', resizeCanvas); | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment