[JavaScript30] ๐Ÿ–Œ 08. FUN WITH HTML5 CANVAS

17024 ๋‹จ์–ด JavaScriptjavascript30JavaScript

08. ๐Ÿ–Œ FUN WITH HTML5 CANVAS

HTML์— canvas๋ฅผ ์ด์šฉํ•ด ๊ฐ์ข… ํšจ๊ณผ๋ฅผ ๋„ฃ์–ด๋ด„.

์ดˆ๊ธฐ์ฝ”๋“œ

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>HTML5 Canvas</title>
</head>
<body>
    <canvas id="draw" width="800" height="800"></canvas>
</body>
<style>
    html, body{
        margin: 0;
    }
</style>
</html>

๐ŸŒ ์•Œ๊ฒŒ๋œ ๊ฒƒ

๐Ÿ‘‰ canvas

  • const ctx = canvas.getContext('2d');

    • ์บ”๋ฒ„์Šค์˜ ๋“œ๋กœ์ž‰ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•จ. 2d์ธ๊ฒฝ์šฐ 2d๋ฅผ ์ž‘์„ฑ.
    • webgl | experimental-webgl: 3์ฐจ์› ๋ Œ๋”๋ง ์ปจํ…์ŠคํŠธ
    • webg2 : 3์ฐจ์› ๋ Œ๋”๋ง ์ปจํ…์ŠคํŠธ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” `WebGLRenderingContext๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
    • bitmaprenderer : ์บ”๋ฒ„์Šค์˜ ์ปจํ…์ธ ๋ฅผ ์ฃผ์–ด์ง„ ImageBitmap (en-US)์œผ๋กœ ๋Œ€์ฒดํ•˜๊ธฐ์œ„ํ•œ ๊ธฐ๋Šฅ๋งŒ์„ ์ œ๊ณตํ•˜๋Š” ImageBitmapRenderingContext (en-US)๋ฅผ ์ƒ์„ฑ
  • 2d์—์„œ ์ง์‚ฌ๊ฐํ˜• , ํ…์ŠคํŠธ, ์„ ์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๊ณ , ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ .

    https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D

์ฑ„์šฐ๊ธฐ ๋ฐ ํš ์Šคํƒ€์ผ

  • ctx.strokeStyle : ๋„ํ˜• ์ฃผ์œ„์˜ ์„ ์— ์‚ฌ์šฉํ•  ์ƒ‰์ƒ ๋˜๋Š” ์Šคํƒ€์ผ. ๊ธฐ๋ณธ๊ฐ’ #000

์„  ์Šคํƒ€์ผ

  • ctx.lineJoin : ๋‘ ์„ ์ด ๋งŒ๋‚˜๋Š” ๋ชจ์„œ๋ฆฌ ์œ ํ˜•์„ ์ •์˜
    • round, bavel, miter(๊ธฐ๋ณธ๊ฐ’)
  • ctx.lineCap : ์ค„ ๋์˜ ์—”๋”ฉ ์œ ํ˜•.
    • butt(๊ธฐ๋ณธ๊ฐ’), round, square
  • ctx.lineWidth : ์„ ์˜ ๋„ˆ๋น„, ๊ธฐ๋ณธ๊ฐ’ 1.0

๊ฒฝ๋กœ

๊ฐœ์ฒด์˜ ๊ฒฝ๋กœ๋ฅผ ์กฐ์ž‘ ๊ฐ€๋Šฅ.

  • beginPath() : ํ•˜์œ„ ๊ฒฝ๋กœ ๋ชฉ๋ก์„ ๋น„์›Œ ์ƒˆ ๊ฒฝ๋กœ๋ฅผ ์‹œ์ž‘.
  • moveTo() : ์ƒˆ ํ•˜์œ„ ๊ฒฝ๋กœ์˜ ์‹œ์ž‘์ ์„ (x, y)์ขŒํ‘œ๋กœ ์ด๋™ํ•จ.
  • lineTo() : ํ˜„์žฌ ํ•˜์œ„ ๊ฒฝ๋กœ์˜ ๋งˆ์ง€๋ง‰ ์ ์„ ์ง€์ •๋œ (x, y)์ขŒํ‘œ์— ์ง์„ ์œผ๋กœ ์—ฐ๊ฒฐํ•จ.
  • stroke : ํ˜„์žฌ ํš ์Šคํƒ€์ผ๋กœ ํ˜„์žฌ ํ•˜์œ„ ๊ฒฝ๋กœ๋ฅผ ํš์„ ๊ทธ์Œ.

๐ŸŒ ๊ณผ์ •

๐Ÿ‘‰ 1. ๊ทธ๋ฆฌ๊ธฐ ํšจ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ณธ ์„ค์ •.

 const canvas = document.querySelector("#draw");
const ctx = canvas.getContext('2d');

// canvas resize
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

ctx.strokeStyle = '#BADA55';
ctx.lineJoin = 'round';
ctx.lineCap = 'round'
ctx.lineWidth = 0;

๊ทธ๋ฆด ์บ”๋ฒ„์Šค(#draw)๋ฅผ canvas์— ์ €์žฅํ•˜๊ณ  ctx์— canvas์˜ ๊ทธ๋ฆฌ๊ธฐ ๋Œ€์ƒ์ด ๋˜๋Š” context๋ฅผ ์–ป์Œ.

width์™€ height์˜๋ฅผ ์„ค์ •ํ•˜๊ณ ,

์„ ์˜ ์ƒ‰(strokeStyle), ์„ ์˜ ๋๋ชจ์–‘(lineCap), ๋‘๊ฐœ ์„ ์ด ๋งŒ๋‚˜๋Š” ์ง€์ ์˜ ๋ชจ์–‘(lineJoin)๊ณผ ์„ ์˜ ๋‘๊ผ(lineWidth)์ง€์ •.

๐Ÿ‘‰ 2. ๊ทธ๋ฆฌ๊ธฐ ํšจ๊ณผ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜ ์„ค์ •

let isDrawing = false;
let lastX = 0;
let lastY = 0;

let hue = 0;
let direction = true;

isDrawing์€ ํ˜„์žฌ ๊ทธ๋ฆฌ๊ณ  ์žˆ๋Š”์ง€ ์•„๋‹Œ์ง€ check

lastX์™€ lastY๋ฅผ ์ด์šฉํ•ด ์‹œ์ž‘์ง€์ ์ขŒํ‘œ๋ฅผ ์ง€์ •.

hue๋ฅผ ํ†ตํ•ด ์„ ์˜ ์ƒ‰์„ ๋ณ€๊ฒฝ.

direction์œผ๋กœ ๊ตต๊ธฐ๋ฅผ ์ •ํ•˜๋Š” ๋ฐฉํ–ฅ์„ ์„ค์ •.

๐Ÿ‘‰ 3. ๊ทธ๋ฆฌ๊ธฐ ํšจ๊ณผ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ”๊พธ๋Š” ํ•จ์ˆ˜ ์ž‘์„ฑ

// ๋งˆ์šฐ์Šค๋ฅผ ํด๋ฆญํ•  ๋•Œ ์‹œ์ž‘์ง€์  ์žฌ์„ค์ •.
canvas.addEventListener('mousedown', (e)=>{
    isDrawing = true;
    [lastX, lastY] = [e.offsetX, e.offsetY];
});


canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', ()=>isDrawing = false);
canvas.addEventListener('mouseout', ()=>isDrawing = false);

mouse eventํ™•์ธ.

๐Ÿ‘‰ 4. ๊ทธ๋ฆฌ๊ธฐ ํšจ๊ณผ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜ ์ž‘์„ฑ.

function draw(e){
    // stop the function from running when they are not moused down
    // ๋งˆ์šฐ์Šค๋ฅผ ๋ˆ„๋ฅด์ง€ ์•Š์„ ๋•Œ ๊ธฐ๋Šฅ ์‹คํ–‰ ์ค‘์ง€

    if(!isDrawing) return;
    console.log(e);

    ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
    // ctx.lineWidth = hue;

    ctx.beginPath();
    // start from
    ctx.moveTo(lastX, lastY);
    // goto
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();

    // ๋งˆ์ง€๋ง‰ ์ง€์ ์„ ๋์ง€์ ์œผ๋กœ ์ง€์ •.
    // ๋‹ค์Œ์— ๊ทธ๋ฆด ๋•Œ ์‹œ์ž‘์ง€์ ์ด ์ด์ „ ์ž‘์—…์˜ ๋์ง€์ .
    // lastX = e.offsetX;
    // lastY = e.offsetY;
    [lastX, lastY] = [e.offsetX, e.offsetY];

    hue++;
    // reset
    if(hue >=360){
        hue = 0;
    }

    // ctx.lineWidth++;
    if(ctx.lineWidth >= 100 || ctx.lineWidth <= 1){
        direction = !direction;
    }

    if(direction){
        ctx.lineWidth++;
    }else{
        ctx.lineWidth--;
    }


}

lastX์™€ lastY๋ฅผ ์„ค์ •ํ•ด์คŒ์— ๋”ฐ๋ผ ๋ณ€ํ™”.

hue๊ฐ’ ๋ณ€ํ™”.

๊ทธ ํ›„ direction์— ๋”ฐ๋ผ ๊ตต๊ธฐ์กฐ์ ˆ.

๐Ÿ‘‰ 5. multiply

ctx.globalCompositeOperation = 'multiply';

์ƒ‰์ด ๊ฒน์น˜๊ฒŒ ๋ณด์ด๊ฒŒ ๋จ.

๋” ๋งŽ์€ ์†์„ฑ์ด ๊ณต์‹ ๋ฌธ์„œ์— ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์ž!

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ