[nomadcoder]밈메이커 #2 [2022 UPDATE] PAINTING BOARD

수경·2023년 1월 30일
0
post-thumbnail

그림판 만들기


전체 코드는 맨 밑에 있습니다.

기능 별 코드

변수 설정

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));

fill, draw 버튼

function onModeClick() {
    if (isFilling) {
        isFilling = false
        modeBtn.innerText = "Fill"
    } else {
        isFilling = true
        modeBtn.innerText = "Draw"
    }
}

modeBtn.addEventListener("click", onModeClick);

destroy(초기화) 버튼

//초기화 버튼, 되돌리수는 없으므로 그냥 하얗게 덮어줌
function onDestroyClick() {
    ctx.fillStyle = "white"
    ctx.fillRect(0,0,CANVAS_WIDTH, CANVAS_HEIGHT);
}

destroyBtn.addEventListener("click", onDestroyClick);

erase(지우개) 버튼

//지우개 버튼
function onEraseClick() {
    ctx.strokeStyle = "white";
    isFilling = false;
    modeBtn.innerText = "Fill"
}

eraseBtn.addEventListener("click", onEraseClick);

전체코드(html, css, js)

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);
profile
웹백엔드개발자를 꿈꾸는

0개의 댓글