230428 - canvas

๋ฐฑ์Šน์—ฐยท2023๋…„ 4์›” 28์ผ
1

๐Ÿšฉ Canvas

canvas tag / API

๐Ÿ“ ์„ค๋ช…

  • ํ™”๋ฉด์— ๊ทธ๋ฆผ์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐ„์„ ๋งŒ๋“ค์–ด์„œ ๋งˆ์šฐ์Šค๋กœ ๊ทธ๋ฆผ์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ฒŒ ํ•ด ์ฃผ๋Š” tag / API


โœ’๏ธ ์‚ฌ์šฉ๋ฒ•

์ž…๋ ฅ

css

body { font-family: Verdana, Geneva, Tahoma, sans-serif; background: #aaa; height: 100vh; display: flex; justify-content: center; align-items: center; }

.menu { display: flex; justify-content: space-around; align-items: center; background: #333; color: #fff; padding: 10px; border-radius: 10px 10px 0 0; }
canvas { background: #fff; border-radius: 0 0 10px 10px; }
input { width: 50px; height: 30px; text-align: center; outline: none; border: none; }
.item { display: flex; align-items: center; column-gap: 10px; }
button { height: 35px; padding: 0 15px; border-radius: 7px; }
button:hover { background: powderblue; }

html

<div class="container">
      <div class="menu">
        <div class="item">
          <label for="color">Color</label>
          <input type="color" name="" id="color" />
        </div>
        <div class="item">
          <label for="size">Size</label>
          <input type="number" name="" id="size" min="1" max="10" value="5" />
        </div>
        <button class="clear">Clear</button>
        <button class="save">Save to Image</button>
      </div>
      <canvas width="600" height="400"></canvas>
    </div>

js

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d"); // 2d ๊ทธ๋ฆผ์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐ„ ์„ค์ •

const size = document.querySelector("#size");
const color = document.querySelector("#color");

const clear = document.querySelector(".clear");
const save = document.querySelector(".save");

let isPainting = false; // ๊ทธ๋ฆผ๊ทธ๋ฆฌ๋Š” ์ค‘์ธ์ง€ ์•„๋‹Œ์ง€ ํŒ๋‹จํ•˜๋Š” ๋ณ€์ˆ˜
let lineSize = 5; // ๋ผ์ธ ๋‘๊ป˜ 5๋กœ ์‹œ์ž‘

// ๋ฐฐ๊ฒฝ์ƒ‰ ๋ฐ”๊พธ๊ธฐ ์œ„ํ•ด ์„ ์–ธ
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);

// save. ์ด๋ฏธ์ง€๋กœ ์ €์žฅ
//blob - binary large object(์šฉ๋Ÿ‰์ด ํฐ ํŒŒ์ผ์„ ์˜๋ฏธ)
save.addEventListener("click", () => {
  canvas.toBlob((blob) => {  // toBlob(); - ํŒŒ์ผ์„ ์ €์žฅํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    const a = document.createElement("a"); // ์—†๋Š” aํƒœ๊ทธ๋ฅผ ์ƒ์„ฑ
    a.href = URL.createObjectURL(blob); // ํŒŒ์ผ์˜ ๊ฐ€์ƒ URL ์ฃผ์†Œ๋ฅผ ๋งŒ๋“ค์–ด ์คŒ
    a.download = "drawing.jpg"; // ์ €์žฅํ•  ํŒŒ์ผ ์ด๋ฆ„ ์„ค์ • (png ํˆฌ๋ช…์œผ๋กœ๋„ ๊ฐ€๋Šฅ - ๋ฐฐ๊ฒฝ์ƒ‰ ์„ค์ • ์•ˆ ํ–ˆ์„ ์‹œ)
    a.click();
    // console.log(a);
  });
});

// clear
clear.addEventListener("click", () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // (์‹œ์ž‘์œ„์น˜ x, ์‹œ์ž‘์œ„์น˜ y, ์ž์šธ ํฌ๊ธฐ ๊ฐ€๋กœ, ์ง€์šธ ํฌ๊ธฐ ์„ธ๋กœ)
});

// ์„  ๊ตต๊ธฐ ์ ์šฉ
size.addEventListener("change", (event) => {
  // console.log(event.target.value);
  lineSize = event.target.value; // ์„ ํƒํ•œ ์ˆซ์ž // *
});

// ์ƒ‰์ƒ ์ ์šฉ
color.addEventListener("change", (event) => {
  // console.log(event.target.value); // hex๊ฐ’์ด ๋‚˜์˜ด
  ctx.strokeStyle = event.target.value;
});

canvas.addEventListener("mousedown", (event) => {
  // console.log(event);
  isPainting = true; // ๊ทธ๋ฆผ ๊ทธ๋ฆฌ๋Š” ์ค‘
  ctx.beginPath(); // ์ƒˆ๋กœ์šด ๊ฒฝ๋กœ ์ƒ์„ฑ, ๊ทธ๋ฆฌ๊ธฐ ์‹œ์ž‘
  ctx.moveTo(event.offsetX, event.offsetY); // ๋งˆ์šฐ์Šค ์œ„์น˜ ์ขŒํ‘œ๊ฐ’
});

canvas.addEventListener("mousemove", () => {
  // ๋งˆ์šฐ์Šค๋ฅผ ๋ˆ„๋ฅด์ง€ ์•Š์•˜์„ ๋–„๋Š” ์ž‘๋™x
  if (!isPainting) {
    return;
  }

  ctx.lineWidth = lineSize; // *
  ctx.lineCap = "round";
  ctx.lineJoin = "round"; //์„ ๊บฝ์ด๋Š” ์Šคํƒ€์ผ

  ctx.lineTo(event.offsetX, event.offsetY); // ์„ ์„ ๊ทธ๋ฆผ
  ctx.stroke(); // ์œค๊ณฝ์„ ์„ ๊ทธ๋ฆผ
});

canvas.addEventListener("mouseup", (event) => {
  isPainting = false; //๊ทธ๋ฆฌ๊ธฐ ๋
});

// ๋งˆ์šฐ์Šค๊ฐ€ ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋ฒ—์–ด๋‚˜๋ฉด ๋ฉˆ์ถ”๊ฒŒ ํ•จ
canvas.addEventListener("mouseout", (event) => {
  isPainting = false; // ๊ทธ๋ฆฌ๊ธฐ ๋
});

์ถœ๋ ฅ

  • ์ด๋ฏธ์ง€๋กœ ๋Œ€์ฒด


๐Ÿ”— ์ฐธ๊ณ  ๋งํฌ & ๋„์›€์ด ๋˜๋Š” ๋งํฌ






profile
๊ณต๋ถ€ํ•˜๋Š” ๋ฒจ๋กœ๊ทธ

0๊ฐœ์˜ ๋Œ“๊ธ€