클론코딩/노마드코더 그림 앱

[클론코딩/그림 앱] 노마드 코더 그림 앱 클론코딩 #2 Meme Maker

기록하는_사람 2022. 10. 27. 19:19

Meme Maker - 이미지 띄우기

📌 이미지 url은 실제 인터넷에 존재하지 않음. 

      브라우저를 위한 url. 브라우저가 자신의 메모리에 있는 파일을 드러내는 방식. 

...
function onFileChange(event) {
    const file = event.target.files[0];
    const url = URL.createObjectURL(file);
    const image = new Image();

    image.src = url;
}
...

 

📄 index.html

    ...
    <!-- image -->
    <input type="file" accept="image/*" id="file" />

    <!-- js -->
    <script src="app.js"></script>
</body>
</html>

📄 app.js

...
const fileInput = document.getElementById("file");
...
function onFileChange(event) {
    const file = event.target.files[0];
    const url = URL.createObjectURL(file);
    const image = new Image();

    image.src = url;
    image.onload = function() {
        ctx.drawImage(image, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        fileInput.value = null;
    }
}
...
fileInput.addEventListener("change", onFileChange);

 

Meme Maker - 텍스트 추가하기 

📌 ctx.save() : ctx의 현재 상태, 색상, 스타일 등을 저장함. 

      ctx.restore() : 저장된 상태로 돌아감.

      save()와 restore() 사이에 수정된 코드는 저장되지 않음. 

 

📄 index.html

    ...
    <!-- text -->
    <input type="text" placeholder="Write and then double click" id="text" />

    <!-- js -->
    <script src="app.js"></script>
</body>
</html>

📄 app.js

...
const textInput = document.getElementById("text");
...
function onDoubleClick(event) {
    ctx.save();
    if(text !== "") {
        const text = textInput.value;
        ctx.lineWidth = 1;
        ctx.font = "48px serif";
        ctx.strokeText(text, event.offsetX, event.offsetY);
        ctx.restore();
    }
}

canvas.addEventListener("dblclick", onDoubleClick);
...

 

Meme Maker - 선 둥글게 

📄 app.js

...
ctx.lineWidth = lineWidth.value;
ctx.lineCap = "round";
...

 

Meme Maker - 이미지 다운로드

📄 index.html

    ...
    <!-- save image -->
    <button id="save-btn">Save Image</button>

    <!-- js -->
    <script src="app.js"></script>
</body>
</html>

📄 app.js

...
const saveBtn = document.getElementById("save-btn");
...
function onSaveClick() {
    const url = canvas.toDataURL();
    const a = document.createElement("a");

    a.href = url;
    a.download = "myDrawing.png";
    a.click();
}
...
saveBtn.addEventListener("click", onSaveClick);

 

Meme Maker - css

📌 all : unset; 

: 모든 css 속성 제거. 

 

📌 label 태그를 사용해서, input을 클릭한 것처럼 만들 수 있음. 

: label 태그의 for값이랑 id값이 같으면, text를 클릭했을 때 id값의 input을 실행시킴. 

...
        <label for="file">
            <!-- image -->
            Add Image
            <input type="file" accept="image/*" id="file" />
        </label>
...

 

📄 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Meme Maker</title>
    <link rel="stylesheet" href="styles.css" />
</head>
<body>
    <!-- color palette -->
    <div class="color-options">
        <!-- color -->
        <input id="color" type="color" />
        
        <!-- color palette -->
        <div
            class="color-option"
            style="background-color: #DF0101"
            data-color="#e74c3c"
        ></div>
        <div
            class="color-option"
            style="background-color: #FF8000"
            data-color="#d35400"
        ></div>
        <div
            class="color-option"
            style="background-color: #f1c40f"
            data-color="#f1c40f"
        ></div>
        <div
            class="color-option"
            style="background-color: #D0FA58"
            data-color="#27ae60"
        ></div>
        <div
            class="color-option"
            style="background-color: #298A08"
            data-color="#27ae60"
        ></div>
        <div
            class="color-option"
            style="background-color: #58D3F7"
            data-color="#34495e"
        ></div>
        <div
            class="color-option"
            style="background-color: #013ADF"
            data-color="#3498db"
        ></div>
        <div
            class="color-option"
            style="background-color: #0B2161"
            data-color="#8e44ad"
        ></div>
        <div
            class="color-option"
            style="background-color: #4B088A"
            data-color="#95a5a6"
        ></div>
        <div
            class="color-option"
            style="background-color: #BDBDBD"
            data-color="#95a5a6"
        ></div>
        <div
            class="color-option"
            style="background-color: #000000"
            data-color="#95a5a6"
        ></div>
    </div>

    <canvas></canvas>
    
    <div class="btns">
        <!-- line width -->
        <input id="line-width" type="range" min="1" max="10" vlaue="5" step="0.5" />

        <!-- color fill -->
        <button id="mode-btn">Fill</button>

        <!-- reset -->
        <button id="destroy-btn">Destroy</button>

        <!-- eraser -->
        <button id="eraser-btn">Eraser</button>

        <label for="file">
            <!-- image -->
            Add Image
            <input type="file" accept="image/*" id="file" />
        </label>

        <!-- text -->
        <input type="text" placeholder="Add text here" id="text" />

        <!-- save image -->
        <button id="save-btn">Save Image</button>
    </div>

    <!-- js -->
    <script src="app.js"></script>
</body>
</html>

📄 styles.css

@import "reset.css";

body {
    display: flex;
    gap:20px;
    justify-content: space-between;
    align-items: flex-start;
    background-color: blanchedalmond;
    padding:20px;
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

canvas {
    width: 800px;
    height: 800px;
    border-radius: 10px;
    background-color: white;
}

body {
    display: flex;
    justify-content: center;
    align-items: center;
}

.btns {
    display: flex;
    flex-direction: column;
    gap:20px;
}

.color-options {
    display: flex;
    flex-direction: column;
    gap: 15px;
    align-items: center;
}

.color-option {
    width: 50px;
    height: 50px;
    border: 5px solid white;
    border-radius: 25px;
    cursor: pointer;
    transition: transform ease-in-out .1s;
}

.color-option:hover {
    transform: scale(1.2);
}

input#color {
    background-color: white;
}

button, label {
    all: unset;   
    padding: 10px 0px;
    text-align: center;
    background-color: tomato;
    color: white;
    font-weight: 500;
    cursor: pointer;
    border-radius: 15px;
    transition: opacity linear .1s;
}

button:hover {
    opacity: 0.7;
}

input#text {
    all: unset;   
    padding: 10px 0px;
    text-align: center;
    background-color: white;
    font-weight: 500;
    border-radius: 15px;
}

input#file {
    display: none;
}