/Painting-App-Toy-Project

Painting App with Vanilla JS

Primary LanguageCSS

๐Ÿ– Painting-App-Toy-Project ๐Ÿ–

Vanilla JS ๋กœ ์ œ์ž‘ํ•œ ๋ฐ˜์‘ํ˜• ๊ทธ๋ฆผํŒ ์›น์ž…๋‹ˆ๋‹ค.
์ถœ์ฒ˜: ๋…ธ๋งˆ๋“œ์ฝ”๋” ๊ฐ•์˜ ํ™œ์šฉ

์บ”๋ฒ„์Šค ํฌ๊ธฐ ์ž…๋ ฅ ์ „(์›น ์‹คํ–‰ ์‹œ)

app_size1 painting_web_screenshot

์บ”๋ฒ„์Šค ํฌ๊ธฐ ์ž…๋ ฅ ํ›„

app_size2 websize_2

javascript ๋งŒ์„ ์ด์šฉํ•˜์—ฌ ์ œ์ž‘ํ•œ ๊ทธ๋ฆผํŒ์„ ๊ตฌํ˜„ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ํ•œ javascript code

const colors = document.getElementsByClassName(`jsColor`);
const canvas = document.getElementById(`jsCanvas`);
const range = document.getElementById(`jsRange`);
const clear = document.getElementById(`jsClear`);
const fill = document.getElementById(`jsFill`);
const saveBtn = document.getElementById(`jsSave`);

const canvasSizeForm = document.querySelector(`.defineCanvasSize`);
const inputWidth = canvasSizeForm.querySelector(`#jsWidth`);
const inputHeight = canvasSizeForm.querySelector(`#jsHeight`);
const sizeBtn = document.getElementById(`jsCanvasSizeBtn`);

const INITIAL_COLOR = `#1a1a1a`;
const context = canvas.getContext(`2d`);
let painting = false;
let filling = false;

context.strokeStyle = INITIAL_COLOR;
context.fillStyle = INITIAL_COLOR;
context.lineWidth = 2.5;

let widthValue = 0;
let heightValue = 0;

canvas.style.width = widthValue;
canvas.style.height = heightValue;

๋ณ€์ˆ˜ ์„ ์–ธ๊ณผ ๊ธฐ๋ณธ ๊ฐ’๋“ค ์ •์˜.
๊ธฐ๋ณธ ์บ”๋ฒ„์Šค์˜ ์‚ฌ์ด์ฆˆ๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ธฐ ์ „์—๋Š” ์บ”๋ฒ„์Šค๊ฐ€ ๋ณด์ด์ง€ ์•Š๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.


function canvasSetting() {
  canvas.style.width = "";
  canvas.style.height = "";

  widthValue = inputWidth.value;
  heightValue = inputHeight.value;

  context.fillStyle = `white`;
  context.fillRect(0, 0, widthValue, heightValue);

  canvas.style.width = widthValue;
  canvas.style.height = heightValue;

  canvas.width = widthValue;
  canvas.height = heightValue;
}

์บ”๋ฒ„์Šค ์„ธํŒ…๊ณผ ๊ธฐ๋ณธ ๊ฐ’๋“ค์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜.

function stopPainting() {
  painting = false;
}

function startPainting() {
  painting = true;
}

function onMouseLeave() {
  stopPainting();
}

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

  if (!painting) {
    context.beginPath();
    context.moveTo(x, y);
  } else {
    context.lineTo(x, y);
    context.stroke();
  }
}

๋งˆ์šฐ์Šค๊ฐ€ ์บ”๋ฒ„์Šค ์œ„์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผฐ์„ ๋•Œ, ์ƒํ™ฉ์— ๋”ฐ๋ผ ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฌ๊ฑฐ๋‚˜ ๊ทธ๋ฆผ ๊ทธ๋ฆฌ๋Š” ๊ฒƒ์„ ๋ฉˆ์ถ”๊ฒŒ ํ•˜๋Š” ํ•จ์ˆ˜๋“ค ์ž…๋‹ˆ๋‹ค.
๋งˆ์šฐ์Šค๊ฐ€ ์›€์ง์ผ ๋•Œ ํฌ์ธํ„ฐ์˜ ์œ„์น˜๋ฅผ offsetX , offsetY ๋กœ ๊ฐ€์ ธ์™€ path(๋ณด์ด์ง€ ์•Š๋Š”) ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค
ํด๋ฆญ์ด ๋ฐœ์ƒํ•œ ์‹œ์ ์— paiting ์„ true ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ผ์ธ์„ ๊ทธ๋ฆฌ๋„๋ก ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

function handleColorClick() {
  const color = event.target.style.backgroundColor;

  context.strokeStyle = color;
  context.fillStyle = color;
}

ํŒ”๋ ˆํŠธ์— ํ•ด๋‹นํ•˜๋Š” ์ƒ‰์„ ํด๋ฆญํ–ˆ์„ ๋•Œ, ํŽ˜์ธํŠธ(fillStyle)์™€ ๋ธŒ๋Ÿฌ์‰ฌ(strokeStyle)์˜ ์ƒ‰์ƒ์„ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
๋ฒ„ํŠผ์ด ํด๋ฆญ๋์„ ๋•Œ, ํด๋ฆญ๋œ ๋ฒ„ํŠผ์˜ ๋ฐฐ๊ฒฝ์ƒ‰์„ ์ƒ‰์ƒ ๋ณ€์ˆ˜์— ๋„ฃ์–ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

function handleRangeChange() {
  const colorRange = event.target.value;

  context.lineWidth = colorRange;
}

input์˜ value๋กœ ๋ธŒ๋Ÿฌ์‰ฌ์˜ ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

function handleClickFillMode() {
  if (filling === true) {
    filling = false;
    fill.innerText = `Paint`;
  } else {
    filling = true;
    fill.innerText = `Brush`;
  }
}

Paint ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋ธŒ๋Ÿฌ์‰ฌ์—์„œ ํŽ˜์ธํŠธํ†ต์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

function handleCanvasClick() {
  if (filling) {
    context.fillRect(0, 0, widthValue, heightValue);
  }
}

ํŽ˜์ธํŠธํ†ต์œผ๋กœ ์„ค์ • ๋˜์—ˆ์„ ๋•Œ ๋ฐฐ๊ฒฝ์„ ํด๋ฆญํ•˜๋ฉด, ์ƒ‰์ด ์น ํ•ด์ง€๋„๋ก ํ•˜๋Š” ํ•จ์ˆ˜ ์ž…๋‹ˆ๋‹ค.
fillRect์— ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐฐ๊ฒฝ ์‚ฌ์ด์ฆˆ ๊ฐ’์„ ์ ์šฉํ•˜์—ฌ ์ƒ‰์ƒ์ด ์ž…ํ˜€์ง‘๋‹ˆ๋‹ค.

function saveClick() {
  const image = canvas.toDataURL();
  const link = document.createElement(`a`);

  link.href = image;
  link.download = `Paint JS by JIREH's Canvas`;
  link.click();
}

function blockRightClick() {
  event.preventDefault();

  alert(`์ €์žฅ์„ ์›ํ•˜์‹œ๋ฉด SAVE ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”`);
}

์ €์žฅ์„ ํ•˜๋Š” Save ๋ฒ„ํŠผ์˜ saveClick ํ•จ์ˆ˜์™€, ๋งˆ์šฐ์Šค ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ €์žฅํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ blockRightClick ํ•จ์ˆ˜ ์ž…๋‹ˆ๋‹ค.
๊ธฐ๋ณธ์ ์œผ๋กœ png ํŒŒ์ผ๋กœ ์ €์žฅ์ด ๊ฐ€๋Šฅํ•˜๊ณ , Paint JS by JIREH's Canvas ๋ผ๋Š” ํŒŒ์ผ๋ช…์œผ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
*JIREH : ์ž‘์„ฑ์ž ๋ณธ์ธ์˜ ์•„ํ‹ฐ์ŠคํŠธ, ๋””์ž์ด๋„ˆ ์‹œ์ ˆ ํ™œ๋™๋ช…

function cleanCanvas() {
  canvasSetting();
  const modifiedRangeValue = document.getElementById(`jsRange`);
  context.lineWidth = modifiedRangeValue.value;
}	

Clean ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๊ธฐ์กด ์‚ฌ์šฉ์ž ์„ธํŒ…๊ฐ’์œผ๋กœ ์žฌ์„ค์ • ํ•˜๊ณ  ๋ธŒ๋Ÿฌ์‰ฌ ํฌ๊ธฐ๋ฅผ ์ดˆ๊ธฐํ™” ์‹œํ‚ต๋‹ˆ๋‹ค.

if (colors) {
  Array.from(colors).forEach((eachColor) =>
    eachColor.addEventListener(`click`, handleColorClick)
  );
}

if (canvas) {
  canvas.addEventListener(`mousemove`, onMouseMove);
  canvas.addEventListener(`mousedown`, startPainting);
  canvas.addEventListener(`mouseup`, stopPainting);
  canvas.addEventListener(`click`, handleCanvasClick);
  canvas.addEventListener(`contextmenu`, blockRightClick);
}

if (range) {
  range.addEventListener(`input`, handleRangeChange);
}

if (fill) {
  fill.addEventListener(`click`, handleClickFillMode);
}

if (saveBtn) {
  saveBtn.addEventListener("click", saveClick);
}
if (clear) {
  clear.addEventListener(`click`, cleanCanvas);
}

sizeBtn.addEventListener("click", canvasSetting);

๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋“ค์˜ ์ •์˜์ž…๋‹ˆ๋‹ค.

์ œ์ž‘ํ•œ ์›น์œผ๋กœ ๊ทธ๋ฆฐ ๊ทธ๋ฆผ

์Šคํฌ๋ฆฐ์ƒท 2020-08-14 ์˜คํ›„ 5 42 45