목차
첫번째, 개요 및 구성
두번째, SpriteArea 및 MaxRects 알고리즘 구현
이미지 스프라이트(image sprite)란?
여러 개의 이미지를 하나의 이미지로 합쳐서 관리하는 이미지를 의미합니다.
왜 쓸까요?
여러 이미지를 한번에 로딩 시킬 수 있습니다.
이미지 로딩 시 깜빡임을 없애고 개별 이미지에 대한 관리를 따로 하지 않아도 된다는 장점이 있습니다.
UI 화면
반응형이 아닌 적응형 레이아웃을 선택했고(개발시에 참고했던 사이트와 동일)
Desktop 작업용으로 생각했기 때문에 최대 width값을 1440px(좌우 마진 포함한 사이즈. 미포함시 1060px)으로 맞췄습니다.
UI의 경우 최대한 심플하게 구성하였습니다.
일단 이미지를 올리면 4가지 영역으로 구분됩니다.
Drag&Drop 영역 / 파일 목록 영역 / Sprite이미지 영역 / 스타일시트 영역
Drag&Drop 영역
이미지를 직접 드래그할 수도 있고 파일 탐색기에서 선택할 수도 있습니다.
파일의 확장자(png, jpg, jpeg)가 다를시 alert창으로 예외처리를 하였습니다.
파일 목록 영역
올린 이미지의 파일명, 크기, 타입을 나타냅니다. 이미지 옆에 삭제 아이콘을 클릭하면 해당 이미지는 Sprite에서 빠집니다.
Sprite 이미지 영역
실제 Sprite로 보여지는 영역입니다.
MaxRects 알고리즘으로 이미지의 크기에 맞춰 차곡차곡 쌓이며, 공간이 필요하면 내부 캔버스의 크기가 커지고 스크롤링하여 확인 할 수 있습니다.
스타일 시트 영역
사용자가 background-image로 Sprite 이미지를 바로 적용할 수 있도록 상대 좌표와 사이즈가 담긴 CSS 정보입니다.
원본 Sprite 파일에 대한 클래스와 각 내부 이미지의 정보가 담긴 클래스로 구성하였습니다.
또한 실제 Sprite 이미지를 다운받을 수 있는 버튼이 위치해 있습니다.
Skill
React v18 / 순수 CSS / Typescript / webpack v5 / Jest / Jotai / AWS S3, CloudFront
개발사항
프로젝트 세팅 - 최대한 단순하게!
CRA를 사용하지 않고 리액트 동작에 필요한 최소한으로 구성하였습니다.
웹팩
tsx,ts파일을 babel-loader로 트랜스파일링하였고
css는 style-loader를 사용하여 헤더에 스타일 태그로 적용하였습니다.
또한 개발용, 배포용으로 나누어 개발시엔 소스맵과 HMR을 위해 devServer를 사용하였습니다.
Style-lint
ES-Lint와 같이 스타일 파일에도 린트 설정을 하기위해 스타일 린트 설정을 적용하였고
WebStorm IDE의 File Watcher를 통해 저장시에 자동으로 스타일 컨벤션 fix를 적용시켰습니다.
Jest
설정파일에 moduleNameMapper를 이용하여 각종 스타일 파일과 이미지 파일을 모킹시켰고
Sprite 이미지 테스트를 위해 fakeFile을 만들고 개발시 Jotai에 담았기에 테스트용 Jotai Provider로 전역상태에 세팅하여 테스트하였습니다.
it('image 캔버스 테스트', () => {
const fakeFile: Attachment = {
...new File(['hello'], 'hello.png', {
type: 'image/png',
}),
id: 'id',
name: 'hello.png',
size: 1000,
type: 'image/png',
};
const { container } = render(
<JotaiProvider initialValues={[[FilesAtom, [fakeFile]]]}>
<SpriteArea />
</JotaiProvider>,
);
waitFor(() => {
expect(container).toBeInTheDocument();
});
});
컴포넌트 구성
구성이 많지 않으니 컨테이너 컴포넌트들도 layout 폴더로 따로 안빼고 components 폴더에 넣었습니다.
DropArea
이벤트로 직접 드래그앤드롭을 구현하였고 이미지 파일에 직접 uuid로 아이디를 부여하였습니다.
<div
className={files.length > 0 ? 'drop-area' : 'drop-area-empty'}
onDrop={(e) => {
e.preventDefault();
for (let i = 0; i < e.dataTransfer.files.length; i++) {
if (!checkImageFileType(e.dataTransfer.files[i].name)) {
alert('이미지 파일을 넣어주세요');
return;
}
}
const arr = [...e.dataTransfer.files] as Attachment[];
for (const file of arr) {
const id = v4();
// 파일에 아이디 부여
file.id = id;
}
setFiles((f) => {
return [...f, ...arr];
});
}}
onDragOver={(e) => {
e.preventDefault();
}}
>
이번 시간엔 Sprite Generator의 목적, 전체적인 프로젝트 구조와 UI에 대해 살펴 보았습니다.
다음시간 부터 핵심적인 SpriteArea 구성과 MaxRects 알고리즘 구성에 대해 알아보도록 하겠습니다.
* 배포버전 보러가기
* Github
https://github.com/OhWonjae/SpriteGenerator
* Reference
구글링 하면 처음으로 나오는 스프라이트 이미지 제작 사이트를 참고하여 만들었습니다.
(https://www.toptal.com/developers/css/sprite-generator)
* 다음 포스트
두번째, SpriteArea 및 MaxRects 알고리즘 구현
'포트폴리오' 카테고리의 다른 글
(포트폴리오)CaptureMark 제작기 -2편 (vanillaJS 컴포넌트 구현) (1) | 2024.02.06 |
---|---|
(포트폴리오)CaptureMark 제작기 -1편 (아이디어, 기획, 설계, 디자인) (0) | 2024.02.03 |