전체 코드는 맨 밑에 있습니다.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 800;
//컨버스의 크기 설정
canvas.width=CANVAS_WIDTH;
canvas.height=CANVAS_HEIGHT;
const lineWidth = document.getElementById("line-width");
ctx.lineWidth=lineWidth.value;
//배열로 주지않고 HTMLCollection으로 주기 때문에
//문자열 등 유사 배열(Array-like) 객체나 이터러블한 객체를 배열로 만들어주는 메서드
const colorOptions = Array.from(document.getElementsByClassName("color-option"));
const color = document.getElementById("color");
//버튼
const modeBtn = document.getElementById("mode-btn");
const destroyBtn = document.getElementById("destroy-btn");
const eraseBtn = document.getElementById("erase-btn");
let isPainting = false;
let isFilling = false;
//마우스 클릭한 채 움직였을 때
function onMove(event) {
if (isPainting){
ctx.lineTo(event.offsetX, event.offsetY);
ctx.stroke();
}
ctx.moveTo(event.offsetX, event.offsetY);
}
//마우스를 클릭했을 때
function onMouseDown() {
if (isFilling) {
ctx.fillRect(0,0,CANVAS_WIDTH, CANVAS_HEIGHT);
} else {
isPainting = true;
}
}
//마우스를 뗐을 때
function onMouseUp() {
isPainting=false;
ctx.beginPath();
}
canvas.addEventListener("mousemove", onMove);
canvas.addEventListener("mousedown", onMouseDown);
canvas.addEventListener("mouseup", onMouseUp);
//마우스 클릭한 채 캔버스 밖으로 나갔다가 돌아왔을 때 계속 mousedown 상태인 것의 버그 방지
canvas.addEventListener("mouseleave", onMouseUp);
//라인 굵기 조절
function onLineWidthChange(event){
ctx.lineWidth = event.target.value;
}
lineWidth.addEventListener("change", onLineWidthChange);
//컬러 단일 박스 선택시
function onColorChange(event) {
ctx.strokeStyle = event.target.value;
ctx.fillStyle = event.target.value;
}
//컬러 리스트 선택시
function onColorClick(event) {
//console.dir(event.target.dataset.color);
const colorValue = event.target.dataset.color //data-* 이용하여 dataset.*
ctx.strokeStyle = colorValue;
ctx.fillStyle = colorValue;
color.value = colorValue
}
color.addEventListener("change", onColorChange);
//이해안가는 부분
colorOptions.forEach((color) => color.addEventListener("click", onColorClick));
function onModeClick() {
if (isFilling) {
isFilling = false
modeBtn.innerText = "Fill"
} else {
isFilling = true
modeBtn.innerText = "Draw"
}
}
modeBtn.addEventListener("click", onModeClick);
//초기화 버튼, 되돌리수는 없으므로 그냥 하얗게 덮어줌
function onDestroyClick() {
ctx.fillStyle = "white"
ctx.fillRect(0,0,CANVAS_WIDTH, CANVAS_HEIGHT);
}
destroyBtn.addEventListener("click", onDestroyClick);
//지우개 버튼
function onEraseClick() {
ctx.strokeStyle = "white";
isFilling = false;
modeBtn.innerText = "Fill"
}
eraseBtn.addEventListener("click", onEraseClick);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meme Maker</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<canvas></canvas>
<input id = "line-width" type="range" min="1" max="10" value="5" step="0.5"/>
<div>
<input type="color" id="color" />
<div class="color-option" style="background-color:#1abc9c" data-color="#1abc9c"></div>
<div class="color-option" style="background-color:#3498db" data-color="#3498db"></div>
<div class="color-option" style="background-color:#34495e" data-color="#34495e"></div>
<div class="color-option" style="background-color:#27ae60" data-color="#27ae60"></div>
<div class="color-option" style="background-color:#8e44ad" data-color="#8e44ad"></div>
<div class="color-option" style="background-color:#f1c40f" data-color="#f1c40f"></div>
<div class="color-option" style="background-color:#e74c3c" data-color="#e74c3c"></div>
<div class="color-option" style="background-color:#95a5a6" data-color="#95a5a6"></div>
<div class="color-option" style="background-color:#d35400" data-color="#d35400"></div>
<div class="color-option" style="background-color:#bdc3c7" data-color="#bdc3c7"></div>
<div class="color-option" style="background-color:#2ecc71" data-color="#2ecc71"></div>
<div class="color-option" style="background-color:#e67e22" data-color="#e67e22"></div>
<!-- 'data-' 을 이용하면 값을 받을 수 있음 -->
</div>
<button id="mode-btn">Fill</button>
<button id="destroy-btn">Destroy</button>
<button id="erase-btn">Erase</button>
<script src="app.js"></script>
</body>
</html>
styles.css
canvas{
width : 800px;
height: 800px;
border:5px solid black;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
.color-option {
width: 50px;
height: 50px;
cursor: pointer;
}
app.js
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 800;
//컨버스의 크기 설정
canvas.width=CANVAS_WIDTH;
canvas.height=CANVAS_HEIGHT;
const lineWidth = document.getElementById("line-width");
ctx.lineWidth=lineWidth.value;
//배열로 주지않고 HTMLCollection으로 주기 때문에
//문자열 등 유사 배열(Array-like) 객체나 이터러블한 객체를 배열로 만들어주는 메서드
const colorOptions = Array.from(document.getElementsByClassName("color-option"));
const color = document.getElementById("color");
//버튼
const modeBtn = document.getElementById("mode-btn");
const destroyBtn = document.getElementById("destroy-btn");
const eraseBtn = document.getElementById("erase-btn");
let isPainting = false;
let isFilling = false;
//마우스 클릭한 채 움직였을 때
function onMove(event) {
if (isPainting){
ctx.lineTo(event.offsetX, event.offsetY);
ctx.stroke();
}
ctx.moveTo(event.offsetX, event.offsetY);
}
//마우스를 클릭했을 때
function onMouseDown() {
if (isFilling) {
ctx.fillRect(0,0,CANVAS_WIDTH, CANVAS_HEIGHT);
} else {
isPainting = true;
}
}
//마우스를 뗐을 때
function onMouseUp() {
isPainting=false;
ctx.beginPath();
}
//라인 굵기 조절
function onLineWidthChange(event){
ctx.lineWidth = event.target.value;
}
//컬러 단일 박스 선택시
function onColorChange(event) {
//console.log(event.target.value);
ctx.strokeStyle = event.target.value;
ctx.fillStyle = event.target.value;
}
//컬러 리스트 선택시
function onColorClick(event) {
//console.dir(event.target.dataset.color);
const colorValue = event.target.dataset.color //data-* 이용하여 dataset.*
ctx.strokeStyle = colorValue;
ctx.fillStyle = colorValue;
color.value = colorValue
}
function onModeClick() {
if (isFilling) {
isFilling = false
modeBtn.innerText = "Fill"
} else {
isFilling = true
modeBtn.innerText = "Draw"
}
}
//초기화 버튼, 되돌리수는 없으므로 그냥 하얗게 덮어줌
function onDestroyClick() {
ctx.fillStyle = "white"
ctx.fillRect(0,0,CANVAS_WIDTH, CANVAS_HEIGHT);
}
//지우개 버튼
function onEraseClick() {
ctx.strokeStyle = "white";
isFilling = false;
modeBtn.innerText = "Fill"
}
canvas.addEventListener("mousemove", onMove);
canvas.addEventListener("mousedown", onMouseDown);
canvas.addEventListener("mouseup", onMouseUp);
//마우스 클릭한 채 캔버스 밖으로 나갔다가 돌아왔을 때 계속 mousedown 상태인 것의 버그 방지
canvas.addEventListener("mouseleave", onMouseUp);
lineWidth.addEventListener("change", onLineWidthChange);
color.addEventListener("change", onColorChange);
//이해안가는 부분
colorOptions.forEach((color) => color.addEventListener("click", onColorClick));
modeBtn.addEventListener("click", onModeClick);
destroyBtn.addEventListener("click", onDestroyClick);
eraseBtn.addEventListener("click", onEraseClick);