๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
JavaScript/Vanilla JS

[๋ฐ”๋‹๋ผJS๋กœ ๊ทธ๋ฆผํŒ ๋งŒ๋“ค๊ธฐ] Saving the Image

by ์ฝ”๋”ฉํ•˜๋Š” ๋ถ•์–ด 2021. 4. 28.
๋ฐ˜์‘ํ˜•

[์ถœ์ฒ˜-์œ ํŠœ๋ธŒ ๋…ธ๋งˆ๋“œ ์ฝ”๋” Nomad Coders]

https://youtu.be/xOxE40I75GM

 

์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ์„ ํ•ด ๋ณด์ž!

์šฐ์„  canvas์˜ ๋ฐฐ๊ฒฝ์ƒ‰์„ ์ง€์ •ํ•ด์ฃผ์ž.

(๋ฐฐ๊ฒฝ์ƒ‰์„ ์ง€์ •ํ•ด์ฃผ์ง€์•Š์œผ๋ฉด ๋ฐฐ๊ฒฝ์ด ํˆฌ๋ช…ํ•˜๊ฒŒ ๋‚˜์˜ด)

ctx.fillStyle = "white";
ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);

์ € ๋ฉ”๋‰ด๋ฅผ 'context menu'๋ผ๊ณ  ํ•œ๋‹ค

 

์ €์žฅ๋œ ์ด๋ฏธ์ง€

 

 

 

๋งŒ์•ฝ์— ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๊ณ ์‹ถ์ง€์•Š๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋œ๋‹ค.

 

์ถ”๊ฐ€ํ•  ๊ฒƒโ–ผ

function handleCM(event) {
    event.preventDefault();
}
if(canvas) {
    canvas.addEventListener("mousemove", onMouseMove);
    canvas.addEventListener("mousedown", startPainting);
    canvas.addEventListener("mouseup", stopPainting);
    canvas.addEventListener("mouseleave", stopPainting);
    canvas.addEventListener("click", handleCanvasClick);
    canvas.addEventListener("contextmenu", handleCM);  // ์ถ”๊ฐ€ํ•œ ๋ถ€๋ถ„
}

 

 

app.js

const canvas = document.getElementById("jsCanvas");
const ctx = canvas.getContext("2d");
const colors = document.getElementsByClassName("jsColor");
const range = document.getElementById("jsRange");
const mode = document.getElementById("jsMode");

const INITIAL_COLOR = "#2c2c2c"
const CANVAS_SIZE = 700;

canvas.width = CANVAS_SIZE;
canvas.height = CANVAS_SIZE;

ctx.fillStyle = "white";
ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);

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

let painting = false;
let filling = false;

function stopPainting() {
    painting = false;
}

function startPainting() {
    painting = true;
}

function onMouseMove(event) {
    const x = event.offsetX;
    const y = event.offsetY;
    if(!painting){
        ctx.beginPath();
        ctx.moveTo(x, y);
    } else {
        ctx.lineTo(x, y);
        ctx.stroke();
    }
}

function handleColorClick(event) {
    const color = event.target.style.backgroundColor;
    ctx.strokeStyle = color;
    ctx.fillStyle = color;
}

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

function handleModeClick() {
    if(filling === true) {
        filling = false;
        mode.innerText = "Fill";
    } else {
        filling = true;
        mode.innerText = "Paint";
    }
}

function handleCanvasClick() {
    if (filling) {
        ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);  // canvas๋งŒํผ ์ปค์•ผ ํ•œ๋‹ค
    }
}

function handleCM(event) {
    event.preventDefault();
}

if(canvas) {
    canvas.addEventListener("mousemove", onMouseMove);
    canvas.addEventListener("mousedown", startPainting);
    canvas.addEventListener("mouseup", stopPainting);
    canvas.addEventListener("mouseleave", stopPainting);
    canvas.addEventListener("click", handleCanvasClick);
    canvas.addEventListener("contextmenu", handleCM);
}

Array.from(colors).forEach(color => 
    color.addEventListener("click", handleColorClick)
);

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

if(mode) {
    mode.addEventListener("click", handleModeClick);
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋งˆ์šฐ์Šค ์šฐํด๋ฆญ์„ ํ•ด๋„ 'context menu'๊ฐ€ ๋œจ์ง€ ์•Š๋Š”๋‹ค.

 

 

 

๋‹ค์Œ์œผ๋ก  save ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด ๋ณด์ž.

save ๋ฒ„ํŠผ์— ์•Œ๋งž์€ eventlistener๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด์ž.

๋จผ์ € ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋”ฉ์„ ํ•œ๋‹ค.

const canvas = document.getElementById("jsCanvas");
const ctx = canvas.getContext("2d");
const colors = document.getElementsByClassName("jsColor");
const range = document.getElementById("jsRange");
const mode = document.getElementById("jsMode");
const saveBtn = document.getElementById("jsSave");  // ์ถ”๊ฐ€๋œ ๋ถ€๋ถ„

const INITIAL_COLOR = "#2c2c2c"
const CANVAS_SIZE = 700;

canvas.width = CANVAS_SIZE;
canvas.height = CANVAS_SIZE;

ctx.fillStyle = "white";
ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);

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

let painting = false;
let filling = false;

function stopPainting() {
    painting = false;
}

function startPainting() {
    painting = true;
}

function onMouseMove(event) {
    const x = event.offsetX;
    const y = event.offsetY;
    if(!painting){
        ctx.beginPath();
        ctx.moveTo(x, y);
    } else {
        ctx.lineTo(x, y);
        ctx.stroke();
    }
}

function handleColorClick(event) {
    const color = event.target.style.backgroundColor;
    ctx.strokeStyle = color;
    ctx.fillStyle = color;
}

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

function handleModeClick() {
    if(filling === true) {
        filling = false;
        mode.innerText = "Fill";
    } else {
        filling = true;
        mode.innerText = "Paint";
    }
}

function handleCanvasClick() {
    if (filling) {
        ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);  // canvas๋งŒํผ ์ปค์•ผ ํ•œ๋‹ค
    }
}

function handleCM(event) {
    event.preventDefault();
}

function handleSaveClick() {  // ์ถ”๊ฐ€๋œ ๋ถ€๋ถ„
    
}

if(canvas) {
    canvas.addEventListener("mousemove", onMouseMove);
    canvas.addEventListener("mousedown", startPainting);
    canvas.addEventListener("mouseup", stopPainting);
    canvas.addEventListener("mouseleave", stopPainting);
    canvas.addEventListener("click", handleCanvasClick);
    canvas.addEventListener("contextmenu", handleCM);
}

Array.from(colors).forEach(color => 
    color.addEventListener("click", handleColorClick)
);

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

if(mode) {
    mode.addEventListener("click", handleModeClick);
}

if(saveBtn) {  // ์ถ”๊ฐ€๋œ ๋ถ€๋ถ„
    saveBtn.addEventListener("click", handleSaveClick);
}

 

 

 

๋งจ ๋จผ์ € ํ•„์š”ํ•œ๊ฑด canvas์˜ ๋ฐ์ดํ„ฐ๋ฅผ image์ฒ˜๋Ÿผ ์–ป๋Š” ๊ฒƒ์ด๋‹ค.

function handleSaveClick() {
    const image = canvas.toDataURL("image/jpeg");
    console.log(image);
}

save ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ฝ˜์†”์ฐฝ์— image๊ฐ€ ๋‚˜์˜จ๋‹ค.

 

 

 

๋‹ค์Œ์œผ๋ก  ์กด์žฌํ•˜์ง€ ์•Š๋Š” link๋ฅผ ๋งŒ๋“ ๋‹ค. (fake link)

๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ด ๋งํฌ๋กœ ๊ฐ€๋Š” ๋Œ€์‹  URL์„ ๋‹ค์šด๋กœ๋“œํ•˜๋ผ๊ณ  ์ง€์‹œํ•˜๋Š” ๊ฒƒ(?)์„ ๋งŒ๋“ ๋‹ค.

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

save ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ž๋™์œผ๋กœ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ๋œ๋‹ค.
๋‹ค์šด๋กœ๋“œ๋œ image

 

 

 

 

โ€ป ๊ณ ํ™”์งˆ๋กœ ์ €์žฅํ•˜๊ณ ์‹ถ์œผ๋ฉด DataURL์„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๋œ๋‹ค.

(๊ธฐ๋ณธ๊ฐ’์ด png)

const image = canvas.toDataURL();
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€