티스토리 뷰

반응형

그리기, 채우기, 전체 삭제, 다운로드 기능이 있는 그림판.

 

HTML - BODY

<body class="flex-column">
    <canvas id="canvas"></canvas>
    <div class="controls flex-column">
      <div class="controls_range">
        <input type="range" id="range" min="0.1" max="5.0" value="2.5" step="0.1" />
      </div>
      <div class="controls_btns">
        <button id="mode_btn">Draw Mode</button>
        <button id="clear_btn">Clear</button>
        <button id="save_btn">Save</button>
      </div>
      <div class="controls_colors" id="colors">
        <div class="controls_color" style="background-color: rgb(44, 44, 44)"></div>
        <div class="controls_color" style="background-color: rgb(255, 255, 255)"></div>
        <div class="controls_color" style="background-color: rgb(255, 59, 48)"></div>
        <div class="controls_color" style="background-color: rgb(255, 149, 0)"></div>
        <div class="controls_color" style="background-color: rgb(255, 204, 0)"></div>
        <div class="controls_color" style="background-color: rgb(76, 217, 99)"></div>
        <div class="controls_color" style="background-color: rgb(90, 200, 250)"></div>
        <div class="controls_color" style="background-color: rgb(5, 121, 255)"></div>
        <div class="controls_color" style="background-color: rgb(88, 86, 214)"></div>
      </div>
    </div>
  </body>

 

Javascript

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const colors = document.getElementsByClassName("controls_color");
const range = document.getElementById("range");
const mode = document.getElementById("mode_btn");
const save = document.getElementById("save_btn");
const clear = document.getElementById("clear_btn");

const INIT_FILL_COLOR = "rgb(255, 255, 255)";
const INIT_STROCKE_COLOR = "rgb(44, 44, 44)";

canvas.width = 500;
canvas.height = 500;

ctx.fillStyle = "rgb(255, 255, 255)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.lineWidth = 2.5;

changeColor(INIT_STROCKE_COLOR);

let painting = false;
let filling = false;

function stopPainting() {
  painting = false;
  ctx.closePath();
}

function startPainting() {
  if (!filling) {
    painting = true;
    ctx.beginPath();
    ctx.moveTo(x, y);
  }
}

function onMouseMove(event) {
  const x = event.offsetX;
  const y = event.offsetY;

  if (painting) {
    ctx.lineTo(x, y);
    ctx.stroke();
  }
}

function handleColorClick(event) {
  changeColor(event.target.style.backgroundColor);
}

function changeColor(color) {
  ctx.strokeStyle = color;
  ctx.fillStyle = color;

  Array.from(colors).forEach((e) => {
    if (e.classList.contains("active") && e.style.backgroundColor !== color) {
      e.classList.remove("active");
    } else if (e.style.backgroundColor === color && !e.classList.contains("active")) {
      e.classList.add("active");
    }
  });
}

function handleRangeChange(event) {
  ctx.lineWidth = event.target.value;
}

function handleModeClick() {
  filling = !filling;

  if (filling) {
    mode.innerText = "Fill Mode";
  } else {
    mode.innerText = "Draw Mode";
  }
}

function handleCanvasClick() {
  if (filling) ctx.fillRect(0, 0, canvas.width, canvas.height);
}

function handleSaveClick() {
  const image = canvas.toDataURL();
  const link = document.createElement("a");
  link.href = image;
  link.download = "Paint";
  link.click();
}

function handleClearClick() {
  ctx.fillStyle = INIT_FILL_COLOR;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = ctx.strokeStyle;
}

canvas.addEventListener("mousemove", onMouseMove);
canvas.addEventListener("mousedown", startPainting);
canvas.addEventListener("mouseup", stopPainting);
canvas.addEventListener("mouseleave", stopPainting);
canvas.addEventListener("click", handleCanvasClick);

Array.from(colors).forEach((e) => {
  e.addEventListener("click", handleColorClick);
});

range.addEventListener("input", handleRangeChange);
mode.addEventListener("click", handleModeClick);
save.addEventListener("click", handleSaveClick);
clear.addEventListener("click", handleClearClick);

 

CSS

@import "reset.css";
body {
  background-color: #e5e7e9;
  padding: 50px 0px;
}

.flex-column {
  display: flex;
  flex-direction: column;
  align-items: center;
}

#canvas {
  width: 500px;
  height: 500px;
  background-color: white;
  border-radius: 15px;
  box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
}

.controls {
  margin-top: 80px;
}

.controls_btns,
.controls_range {
  margin-bottom: 30px;
}

.controls_btns button {
  all: unset;
  cursor: pointer;
  background-color: white;
  padding: 5px 0px;
  width: 100px;
  text-align: center;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
  border: 2px solid rgba(0, 0, 0, 0.2);
  color: rgba(0, 0, 0, 0.8);
  text-transform: uppercase;
  font-weight: 800;
  font-size: 12px;
}

.controls_btns button:active {
  transform: scale(0.97);
}

.controls_colors {
  display: flex;
}

.controls_colors .controls_color {
  width: 50px;
  height: 50px;
  border-radius: 25px;
  cursor: pointer;
  box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
  margin: 1px;
}

.controls_colors .controls_color.active {
  box-shadow: 0 7px 11px rgb(224, 10, 231), 0 4px 7px rgb(42, 168, 90);
}
반응형

'note..' 카테고리의 다른 글

expo 시작하기  (0) 2022.03.21
심심해서 찾아본 Wordle의 정답 알아내기..  (0) 2022.03.20
신림역 쪽 괜찮은 스터디카페  (0) 2022.03.12
[HTML + Javascript] Wordle 만들어보기  (0) 2022.03.11
비밀번호 암호화  (0) 2022.02.08
댓글
반응형
최근에 올라온 글
Total
Today
Yesterday
글 보관함
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31