JS과제를 마무리하고 React를 배우기 전에 간단한 프로젝트로 정리하면 좋을거 같아 미니 프로젝트를 하기로 마음 먹었습니다.
인스타그램으로 인생네컷 코딩 강의가 떠 있는것을 보고 한번 직접 만들어보면 좋을거 같다고 생각하였고 배웠던 내용들과 HTML, CSS를 같이 활용하면 좋을거 같다고 생각되어 시작하게 되었습니다.
저번에도 Todo-List를 만들때 figma를 통해 직접 디자인을 해보자고 마음먹었지만 결국 템플릿을 사용해서 조금 수정하는것으로 마무리 했었습니다 😢
이번에는 정말 직접 하나하나 디자인해서 만들어보자 생각하였고 인생네컷 앱의 이미지를 참고하여 디자인을 했습니다.

참고 : 인생네컷
항상 색을 고르는데에 있어서 디자인을 잘 알지 못해 조화롭지 못한 색을 많이 사용했었습니다.
그래서 Adobe Color를 참고한 이미지의 테마색을 가져와 사용했습니다.

모달팝업 디자인과 더 많은것을 만들고 싶었지만, Figma가 미숙하여 디자인에 너무 많은 시간을 쓰기에는 어렵다고 생각하여 간단한 디자인을 만들었습니다.


강의와 과제를 진행하면서 구성된 디렉토리 구조를 참고하여 진행하였습니다.
인생네컷에 본래 기능과 웹에서 수정할 수 있도록 기능을 생각했습니다.
1. 이미지 등록 / 수정
2. 이미지 미리보기
3. 이미지의 위치 조정
4. 네컷 이미지 다운로드
5. 이미지 사이즈 조절
6. 네컷 프레임 커스텀
이미지를 등록하려면 input 파일을 사용해야했는데 특정 영역 클릭시 input이 동작해야했기 때문에 커스텀하여 만들었습니다.
html
<div class="img-select empty"></div>
<input type="file" class="file-input hidden" accept=".jpeg, .png, .jpg" />
js
const imageUpload = (e) => {
if (e.target.className.includes("drag")) {
e.target.classList.remove("drag");
return;
}
let node = e.target;
$file.click();
$file.onchange = (event) => {
if (node.nodeName === "IMG") {
node = node.parentNode;
}
imagePreview(node, event);
};
};
export const setImagePage = () => {
setDate();
$imageSelects.forEach((item) => (item.onclick = imageUpload));
};
input을 display=none으로 설정하고 영역 클릭시 input을 js로 클릭하도록 구현하였습니다.
이미지 파일을 등록하면 등록한 이미지가 프레임에 보여야 하기 때문에 미리보기를 구현했어야 했습니다.
서버가 있다면 서버에 업로드하고 업로드된 이미지 링크를 통해 미리보기를 가져올 수도 있었지만 서버가 존재하지않고 또 이미지를 등록하고 다시 불러오는것은 네트워크 효율이 좋지않아 FileReader를 통해 미리보기를 구현했습니다.
💡 FileReader객체는 웹 라이브러리가 연속적으로 데이터를 읽을 때 링크 파일을 중단하거나 객체를 스크롤하는
파일의 내용을(혹은 원시 데이터 버퍼로) 읽고 사용자의 컴퓨터에 저장하는 것을 가능하게 합니다
js
const imageRemove = (target) => {
target.innerHTML = "";
};
const imagePreview = (target, event) => {
var reader = new FileReader();
if (!event.target.files[0]) return;
imageRemove(target);
reader.onload = function (event) {
var img = document.createElement("img");
img.className = "img";
img.setAttribute("src", event.target.result);
target.appendChild(img);
target.classList.remove("empty");
dragEvent(img);
};
reader.readAsDataURL(event.target.files[0]);
$file.value = "";
};
이미지를 이동하게 하게 하는방법으로 position : absolute로 top과 left를 주면 되겠다 생각했습니다.
이동하는방법은 알겠지만 그것을 구현하는것이 원하는대로 되지 않아 참고하여 진행하였습니다.
js
const dragEvent = (target) => {
let isPress = false;
let prevPosX = 0;
let prevPosY = 0;
const dragStart = (e) => {
isPress = true;
prevPosX = e.clientX;
prevPosY = e.clientY;
};
const dragEnd = () => {
isPress = false;
};
const moveImage = (e) => {
if (!isPress) return;
target.classList.add("drag");
const posX = prevPosX - e.clientX;
const posY = prevPosY - e.clientY;
prevPosX = e.clientX;
prevPosY = e.clientY;
target.style.left = target.offsetLeft - posX + "px";
target.style.top = target.offsetTop - posY + "px";
};
target.onmousedown = dragStart;
window.onmouseup = dragEnd;
window.onmousemove = moveImage;
};

참고 : drag & drop
canvas요소에 그려진 이미지를 다운받는 방법은 있는데 요소를 이미지로 다운받는 방법은 library를 따로 사용했어야 했습니다.
html2canvas는 캡쳐 라이브러리로 원하는 요소를 이미지 캡쳐하는 방식으로 다운로드 할 수 있습니다.
방식으로는 cdn, npm과 같은 방법이 있는데 저는 다운로드 받아서 적용하였습니다.
버튼 클릭시 요소를 캡쳐해서 파일로 만들어 a 태그의 다운로드로 이미지를 다운받을 수 있습니다.
js
import { get } from "../../utils/dom.js";
import { getDate } from "./date.js";
const $imgFrame = get(".img-frame");
export const capture = () => {
isValidate();
html2canvas($imgFrame).then((canvas) => {
saveAs(canvas.toDataURL("image/jpg"), `${getDate()}.jpg`);
});
};
const saveAs = (uri, filename) => {
let link = document.createElement("a");
if (typeof link.download === "string") {
link.href = uri;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
window.open(uri);
}
};

깃허브 https://github.com/bbung95/four-cut-app
호스팅 https://stunning-pika-8d1e39.netlify.app/
프론트를 시작하면서 html과 css를 잘 다루지 못했었는데 지금 이렇게 직접 디자인도 해보고 퍼블리싱하여 프로젝트를 만들 수 있다는게 조금씩 성장하고 있는게 느껴지는거 같습니다.
기능도 많이 빠진 부분이 있어 아직 많이 부족하지만 조금씩 기능을 추가하면서 업데이트를 해보겠습니다! 🤗