1. html 코드
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Paint App</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link href="./style.css" rel="stylesheet">
</head>
<body>
<main>
<asdie>
<ul class="pallet">
<li>
<button class="red selected" data-color="red">red</button>
</li>
<li>
<button class="blue" data-color="blue">blue</button>
</li>
<li>
<button class="black" data-color="black">black</button>
</li>
<li>
<button class="green" data-color="green">green</button>
</li>
</ul>
<ul>
<li>
<button class="control-btn">
<i class="fa-solid fa-eraser" id="eraser"></i>
</button>
</li>
<li>
<button class="control-btn">
<i class="fa-solid fa-download" id="download"></i>
</button>
</li>
</ul>
</asdie>
<canvas></canvas>
</main>
<script src="./script.js"></script>
</body>
</html>
2. css 코드
*{
margin:0;
padding:0;
box-sizing: border-box;
}
li{
list-style: none;
}
body{
background-color: #384047;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
main{
display: grid;
grid-template-columns: 40px 600px;
column-gap: 10px;
}
button{
width: 40px;
height: 40px;
margin-bottom: 10px;
font-size: 0;
border: 2px solid transparent;
border-radius: 5px;
}
button.red{
background-color: red;
}
button.blue{
background-color: blue;
}
button.black{
background-color: black;
}
button.green{
background-color: green;
}
button.selected{
border: 2px solid white;
}
button.control-btn{
font-size: 16px;
}
button.control-btn.selected{
color: blue;
}
canvas{
width: 600px;
height: 400px;
background: white;
border-radius: 10px;
}
3. js 코드
// DOM 초기화
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const colorBtns = document.querySelectorAll(".pallet button");
const eraserBtn = document.querySelector("#eraser");
const downloadBtn = document.getElementById("download");
// 그리기 설정
let isDrawing = false;
let isErasing = false;
ctx.lineWidth = 5;
ctx.strokeStyle = "red";
//이벤트 리스너
function startDrawing(e){
isDrawing = true;
ctx.beginPath();
ctx.moveTo(e.offsetX, e.offsetY);
}
function stopDrawing(){
isDrawing = false;
ctx.closePath();
}
function Drawing(e){
if(!isDrawing) return;
if(isErasing){
ctx.clearRect(e.offsetX, e.offsetY, 20, 20);
}else{
// 그리기
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
}
}
function startErasing(e){
isErasing = true;
colorBtns.forEach((button) => button.classList.remove("selected"));
e.currentTarget.classList.add("selected");
}
function downloadCanvas(){
const image = canvas.toDataURL("image/png", 1.0);
const linkEl = document.createElement("a");
linkEl.href = image;
linkEl.download = "PaintApp"
linkEl.click();
}
function changeColor(e){
isErasing = false;
ctx.strokeStyle = e.currentTarget.dataset.color;
// 내가 선택한 컬러 활성화
colorBtns.forEach(button => {
if(button === e.currentTarget){
button.classList.add("selected");
} else{
button.classList.remove("selected");
}
});
eraserBtn.classList.remove("selected");
}
// 이벤트 연결
canvas.addEventListener("mousedown", startDrawing);
canvas.addEventListener("mousemove", Drawing);
canvas.addEventListener("mouseup", stopDrawing);
colorBtns.forEach(button => button.addEventListener('click', changeColor));
eraserBtn.addEventListener("click", startErasing);
downloadBtn.addEventListener("click", downloadCanvas);
4. 결과
![](https://velog.velcdn.com/images/uniti0903/post/e873fa68-1461-4b0d-aad7-2693493efac4/image.png)