-
Notifications
You must be signed in to change notification settings - Fork 7
๐ชต 4. Canvas ๊ธฐ๋ณธ ๊ธฐ๋ฅ ๊ตฌํ ์ฃผ์ ์ด์
- ๊ด๋ จ ์ด์ : #16
-
์บ๋ฒ์ค ํฐ์น ์ ๋ ์ด์์ ์คํฌ๋กค๋ง์ด ํ์ฑํ ๋๋
์ด์์,MouseEvent์ TouchEvent๊ฐ ์ ๊ณตํ๋ ์ขํ ์์ฑ์ด ๋ค๋ฅธ
์ด์๋ก ๋๋ก์ ๊ตฌํ์ ์ถ๊ฐ ํ์ต์ด ํ์ํ์ต๋๋ค.
- ํฐ์น๋ก ๊ทธ๋ฆฌ๊ธฐ ์ํด ์บ๋ฒ์ค๋ฅผ ์ฌ๋ผ์ด๋ ํ์ ๋, ํ๋ฉด ์ ์ฒด๊ฐ ์ด๋ํ๋ ์ด์๊ฐ ์์์ต๋๋ค.
- css ์์ฑ์
touch-Event : none
์ถ๊ฐํฉ๋๋ค. - touch ์ด๋ฒคํธ ํธ๋ค๋ฌ์
e.preventDefault()
์ถ๊ฐํ์ฌ ์คํฌ๋กค๋ง ๋ฐฉ์งํฉ๋๋ค.
-
์ฒ์์๋ 2๋ฒ ๋ฐฉ๋ฒ์ผ๋ก ํด๊ฒฐํ๋ ค ํ์ง๋ง,
e.preventDefault()
๋ ํด๋น ์ด๋ฒคํธ์ ๋ชจ๋ ๋์์ ๋ง์๋ฒ๋ฆฌ๊ฒ ๋ค๋ ์๋ฏธ๋ก ์๊ณ ์์๊ธฐ์ ๋ฌด์ธ๊ฐ ์ฐ์ฐํ์ต๋๋ค. -
๋ํด์ ์ง์ ์ ์ฉํด๋ณด๋ ์๋์ ๊ฐ์ ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
Canvas.tsx:113 Unable to preventDefault inside passive event listener invocation.
-
ํจ์๋ธ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ํธ์ถ ๋ด์์ default๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๋ผ๋ ์๋ฏธ์ ๊ฒฝ๊ณ ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์คํฌ๋กค ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํดtouchstart
์touchmove
์ด๋ฒคํธ๋ฅผ ํจ์๋ธ(passive) ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ก ์ค์ ํฉ๋๋ค.ํจ์๋ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ
๋ ์ฑ๋ฅ ํฅ์์ ์ํด ํธ๋ค๋ฌ ๋ด์์e.preventDefault()
๋ฅผ ํธ์ถํ์ง ์์ ๊ฒ์ ๋ธ๋ผ์ฐ์ ์ฐจ์์์ ๋ณด์ฅํ๋ ํธ๋ค๋ฌ์ ๋๋ค. -
touchmove
์ ๊ฒฝ์ฐ ์ฃผ๋ก ๋ชจ๋ฐ์ผ ํ๊ฒฝ์์ ์ฐ์ด๊ณ , ๋ชจ๋ฐ์ผ ํ๊ฒฝ์์๋ ์คํฌ๋กค ๊ธฐ๋ฅ์ด ๋งค์ฐ ์ค์ํ๊ธฐ ๋๋ฌธ์, ์คํฌ๋กค ์ด๋ฒคํธ ๋ฐ์ ์ ๋ง๋คe.preventDefault()
๊ฐ ํธ์ถ๋์๋ ์ง ํ์ธํ๋ ์ ์ฐจ๋ฅผ ์๋ตํ๊ธฐ ์ํด ํจ์๋ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ์ธํ ๋์๋ค๊ณ ํฉ๋๋ค. -
์ ์ค์ ์ off ํ๊ณ touch์ด๋ฒคํธ์์ ๋ค์ e.preventDefault()๋ฅผ ํธ์ถ ๊ฐ๋ฅํ๊ฒ ํ๋ ค๋ฉด, ์๋ ์ฒ๋ผ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ถ์ด๋ฉฐ ์ธ์๋ก ์ค์ ๊ฐ์ฒด๋ฅผ ํ๋ ๋ ๋ณด๋ด์ฃผ๋ฉด ๋ฉ๋๋ค.
window.addEventListener('touchmove', handleTouchMove, { passive: false });
-
ํ์ง๋ง ๊ตณ์ด ๋ธ๋ผ์ฐ์ ์ฐจ์์์ ์ต์ ํ๋ฅผ ์ํด ๋ง์๋์ ์ค์ ์ ํด์ ํ๊ณ ์ถ์ง ์์์ต๋๋ค. css ์์ฑ์ผ๋ก ๊ฐํธํ๊ฒ ์ฌ์ฉ ๊ฐ๋ฅํ 1๋ฒ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
touch-Event : none
์ ๋ํ ์กฐ์ฌ๋ chat-gpt์๊ฒ๋ง ๋ฌผ์ด๋ณด๊ณ ๋ง๋ฌด๋ฆฌํ์์ต๋๋ค.- touch-Event : none ์๋ฆฌ ์๋ ค์ค
-
๊ธฐ๋ณธ ํฐ์น ๋์ ์ฐจ๋จ:
touch-action: none
์ ์ค์ ํ ์์์์๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์คํฌ๋กค, ํ๋/์ถ์์ ๊ฐ์ ํฐ์น ๊ธฐ๋ฐ์ ๊ธฐ๋ณธ ๋์์ ์คํํ์ง ์์ต๋๋ค. ์ด ์์ฑ์ ์ ์ฉํ๋ฉด ํฐ์น๊ฐ ๋ฐ์ํด๋ ๋ธ๋ผ์ฐ์ ๋ ์ด ๋์์ ๋ฌด์ํ๊ณ , ํฐ์น ์ด๋ฒคํธ๋ง JavaScript์์ ์์ ํ ์ ์๊ฒ ๋ฉ๋๋ค. -
๋ธ๋ผ์ฐ์ ์ต์ ํ: ๋ณดํต ๋ธ๋ผ์ฐ์ ๋ ํฐ์น ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋ ๊ธฐ๋ณธ ๋์์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฝ๊ฐ์ ์๊ฐ์ ๊ธฐ๋ค๋ฆฝ๋๋ค.
touch-action: none
์ด ์ค์ ๋์ด ์์ผ๋ฉด, ๋ธ๋ผ์ฐ์ ๊ฐ ๊ธฐ๋ณธ ๋์์ ๋ฏธ๋ฆฌ ์ฐจ๋จํ๊ณ ๊ธฐ๋ค๋ฆฌ์ง ์๊ธฐ ๋๋ฌธ์ ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ํ ์ ์์ต๋๋ค. -
JavaScript๋ก๋ง ํฐ์น ๋์ ์ ์ด: ์ด ์์ฑ์ ์ค์ ํ ์์์์๋ ํฐ์น ๋์์ ์์ ํ JavaScript๋ก ์ ์ดํ ์ ์์ต๋๋ค.
touchmove
,touchstart
,touchend
์ด๋ฒคํธ๋ฅผ ํ์ฉํด ํฐ์น ์ด๋ฒคํธ๋ฅผ ์ํ๋ ๋๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
-
๊ธฐ๋ณธ ํฐ์น ๋์ ์ฐจ๋จ:
- touch-Event : none ์๋ฆฌ ์๋ ค์ค
-
React๋ nativeEvent ๊ฐ์ฒด๋ฅผ ํตํด ์บ๋ฒ์ค ์ขํ๋ฅผ ๊ธฐ์ค์ผ๋ก ํ x์ขํ์ y์ขํ๋ฅผ ๋ฐ๋ก ๋ณด๋ด์ค๋๋ค. nativeEvent๋ React์ SyntheticEvent ๊ฐ์ฒด์์ ๋ธ๋ผ์ฐ์ ์ด๋ฒคํธ ๊ฐ์ฒด ์์ฑ์ ์ง์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ํ์ง๋ง ํฐ์น ์ด๋ฒคํธ์๋ ์ด๋ฐ ์์ฑ์ด ์์ด, ํฐ์น ์์๋ ๊ทธ๋ฆฌ๊ธฐ๋ฅผ ๊ตฌํํ๊ธฐ ์ํด์๋ ์บ๋ฒ์ค ์์ ํฐ์น ์ง์ ์ ์ง์ ๊ณ์ฐํด์ค์ผ ํ์ต๋๋ค.
-
MouseDown์ ๊ฒฝ์ฐ ํฐ์น ํ์ ๋๋ ์๋ํ๋๋ฐ, ์ด๋ ๋ธ๋ผ์ฐ์ ๊ฐ ํฐ์น ์คํฌ๋ฆฐ ์ฅ์น์์ ํฐ์น๋ฅผ ๋ง์ฐ์ค ์ ๋ ฅ์ผ๋ก ์๋ฎฌ๋ ์ด์ ํ๊ธฐ ๋๋ฌธ์ด๋ผ๊ณ ํฉ๋๋ค. touchDown, touchEnd๋ ๋ฐ์ ์ ๋ธ๋ผ์ฐ์ ๊ฐ ํฐ์น ์ ๋ ฅ์ ๋ง์ฐ์ค ์ ๋ ฅ์ผ๋ก ์์์ ์ ํํด์ค๋ค๋ ๊ฒ์ ๋๋ค.
- SyntheticEvent, nativeEvent, TouchEvent, MouseEvent ๊ฐ์ ๊ด๊ณ๋ฅผ ๋ ๊น์ํ๊ฒ ์คํฐ๋ํ ํ์๊ฐ ์์ต๋๋ค.
- mouseEvent, touchEvent, window, html ํ๊ทธ๊ฐ ์ ๊ณตํ๋ ์ขํ ์์ฑ๋ค๋ ์ ํํ ์ ๋ฆฌํด ์ดํดํ ํ์๊ฐ ์์ต๋๋ค. (offsetX, clientX, getBound, getBoundingClientRect(), ๊ทธ ์ธ ๊ธฐํ ๋ฑ๋ฑ..)
- ์๋๋ touchEvent์ clickEvent ๊ฐ์ ๊ด๊ณ์ ๋ํ ๊ธ์ ๋๋ค.
-
MouseEvent์ TouchEvent ๋ ๋ค nativeEvent ๊ฐ์ฒด๋ฅผ ํตํด ์ขํ๋ฅผ ๋ฐ์์ค๊ณ ์์ต๋๋ค.
- click : nativeEvent.offsetX, offsetY ์ฌ์ฉ
- touch : nativeEvent.touches ์ฌ์ฉ
-
touchEvent์ ๊ฒฝ์ฐ ์๋ ๋ผ์ธ์ฒ๋ผ ํฐ์น ์ขํ๋ฅผ ๋ฐฐ์ด๋ก ๋ฐ์์ค๊ฒ ๋๋๋ฐ, ์ด๋ ํฐ์น ํ๋ฉด์ ๊ฒฝ์ฐ ํฐ์น์ ์ด 2๊ฐ ์ด์ ์๊ธธ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
const { clientX, clientY } = e.nativeEvent.touches[0]; //๋ทฐํฌํธ ๊ธฐ์ค ์๋ ์ขํ
- ๊ด๋ จ ์ด์ : #27
-
getImageData
๋ฉ์๋๋ฅผ ํตํด Canvas์ ์ด๋ฏธ์ง ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์์ ํ์ฉํฉ๋๋ค. - ๋ฐ๋ผ์ bfs ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๊ตฌํํ๊ธฐ๋ก ๊ณํํ๋๋ฐ, ๊ฒ์ํด๋ณด๋
Flood Fill
์๊ณ ๋ฆฌ์ฆ์ด๋ผ๊ณ ์ด๋ฏธ ๊ฑฐ์ ์ ์์ผ๋ก ๊ตณ์ด์ง ๋ฐฉ๋ฒ์ด ์์์ต๋๋ค.-
Flood Fill
: ์ฃผ์ด์ง ์์์ ์ผ๋ก๋ถํฐ ์ฐ๊ฒฐ๋ ์์ญ๋ค์ ์ฐพ์๋ด๋ย ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. bfs๋ฅผ ํ์ฉํ๋ ๋ฐฉ์์ด ๊ฐ์ฅ ๋ณดํธ์ ์ธ ๋ฏ ํ๊ณ , ๋ฐ๋ผ์ ๊ธฐ์กด ๊ณํ๋๋ก bfs๋ก ๊ตฌํํ๊ธฐ๋ก ๊ฒฐ์ ํ์์ต๋๋ค.
-
-
์ด๋ฐ ๊ณํ์ ์๋์ ๊ฐ์์ต๋๋ค.
-
getImageData๋ Canvas ์ด๋ฏธ์ง ๋ฐ์ดํฐ๋ฅผ rgba ๊ฐ์ด ๋๋ํ ๋ด๊ธด 1์ฐจ์ ๋ฐฐ์ด๋ก ๊ฐ์ ธ์ต๋๋ค. ๋ฐ๋ผ์ bfs ํจ์ ๋ด์์์ ์ด๋ ์ขํ ๋จ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- x์ถ ์ค๋ฅธ์ชฝ์ผ๋ก 1 pixel ์ด๋ :
+ 4
- y์ถ ์๋๋ก 1 pixel ์ด๋ :
+ (canvas.width * ์ขํy + ์ขํx) * 4
- 4๋ฅผ ๋ํ๊ณ ๊ณฑํด์ฃผ๋ ์ด์ ๋ rgba ๊ฐ์ด ์ด 4๊ฐ์ด๊ธฐ ๋๋ฌธ.
- x์ถ ์ค๋ฅธ์ชฝ์ผ๋ก 1 pixel ์ด๋ :
-
์ฌ์ฉ์๊ฐ ํด๋ฆญํ ์์น ๋ํ
(canvas.width * ์ขํy + ์ขํx) * 4
๊ณต์์ผ๋ก ๊ตฌํ ์ ์์ต๋๋ค. ๊ทธ๋์ ํด๋น ๋ฐฉ๋ฒ์ผ๋ก ์บ๋ฒ์ค์ ์ด๋ ์ง์ ์ ์ ํํ๋ ์ง๋ฅผ ๋จผ์ ๊ตฌํ ํ, ์ ๋จ์๋ฅผ ๋ํ๊ณ ๋นผ๋ฉด์ ํฝ์ ์นธ์ ํ์ํด๊ฐ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํด๋ณด์์ต๋๋ค.const movement = [4, CANVAS_SIZE * 4, -4, -CANVAS_SIZE * 4]; while (searchArray.length > 0) { const currentIndex = searchArray.shift(); //searchArray์ ๊ธธ์ด๊ฐ ์์ง๋ ๋ ๊น์ง ๋ฐ๋ณต for (const move of movement) { const nextIndex = convert(currentIndex! + move); //convert๋ ์์๋ฅผ ์ ์๋ก ์ก์์ฃผ๋ ํจ์ if ( nextIndex >= 0 && nextIndex < pixelArray.length && !checkArray[nextIndex] && checkColorisEqual(nextIndex, beforeColor, pixelArray) //index๊ฐ pixelArray ๊ธธ์ด ์์ ์์ผ๋ฉด์ ๋ฐฉ๋ฌธํ ์ ์๋ index์ด๊ณ , //ํด๋ฆญํ ํฝ์ ์ ์์ด index ์์น์ ์๊ณผ ๊ฐ์ผ๋ฉด ์์น ํ searchArray์ ๋ด๋๋ค. ) { checkArray[nextIndex] = true; fillTargetColor(nextIndex, targetColor, pixelArray); searchArray.push(nextIndex); } } }
-
-
ํ์ง๋ง ์ ์ฒ๋ผ ๊ตฌํํ๊ณ ๋๋ ์์ธ์ ํ์ ํ๊ธฐ ํ๋ ๋ฌดํ ๋ฃจํ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์ง์ํ ์ ์๋ ์์ธ์ ๋ค์๊ณผ ๊ฐ์์ต๋๋ค.
- 1์ฐจ์ ๋ฐฐ์ด ์์์ index๋ฅผ ๋ํ๊ณ ๋นผ๋ ๋ฐฉ์์ด๋ค๋ณด๋ ๊ณ์ฐ์ด ๋ถ๋ช ํํฉ๋๋ค.
- ํน์ 4์ ๋ฐฐ์ ๋จ์ ์ธ๋ฑ์ค๊ฐ ์๋ ๊ณณ์ ๊ฑด๋๋ฆฌ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- checkArray์์ ๊ฐ์ ์ด์ ๋ก ์ ๋๋ก ๋์ํ๋์ง ํ์ ํ๊ธฐ๊ฐ ํ๋ญ๋๋ค.
-
๋ฌธ์ ํด๊ฒฐ์ ์ํด 1์ฐจ์ ๋ฐฐ์ด์ ์ขํ๊ฐ์ ์ฌ์ฉํ๋ ๋ถ๋ถ์ ๊ทธ๋๋ก ๋๊ณ , checkArray ๋ฐฉ๋ฌธ ๋ฐฐ์ด์ 2์ฐจ์ ๋ฐฐ์ด๋ก ๋ง๋ค์ด ํ์ ์๋ฃ ์ขํ๋ค์ ๊ด๋ฆฌํ๊ธฐ๋ก ํ์ต๋๋ค. ์๋๋ ์ ์ ๋ต์ผ๋ก ์์ ํ ์ฝ๋์ ๋๋ค. ์ขํ ์ด๋์ ๊ฐ์์ 2์ฐจ์ ๋ฐฐ์ด(checkArray)์์ ๊ด๋ฆฌํด์ฃผ๊ณ , ๋ฐ๋ณต๋ฌธ ๋ด์์ 2์ฐจ์ ๋ฐฐ์ด์ ๊ฐ์ ์ขํ๋ฅผ 1์ฐจ์ ์ขํ๋ก ๋ณํํด ์ฌ์ฉํ์์ต๋๋ค.
const movement = [[1, 0],[0, -1],[-1, 0],[0, 1]];
while (searchArray.length > 0) {
const [currentX, currentY] = searchArray.shift()!;
for (const move of movement) {
const [nextX, nextY] = [currentX + move[0], currentY + move[1]];
if (
nextX >= 0 &&
nextX < CANVAS_SIZE_WIDTH &&
nextY >= 0 &&
nextY < CANVAS_SIZE_HEIGHT &&
!checkArray[nextY][nextX]
) {
const nextArrayIndex = (nextY * CANVAS_SIZE_WIDTH + nextX) * 4;
// 2์ฐจ์ ๋ฐฐ์ด์ ๊ฐ์ ์ขํ๋ฅผ ์ค์ 1์ฐจ์ ๋ฐฐ์ด์ ์ขํ๋ก ๋ณํ
if (checkColorisEqual(nextArrayIndex, clickColor, pixelArray)) {
checkArray[nextY][nextX] = true;
fillTargetColor(nextArrayIndex, targetColor, pixelArray);
searchArray.push([nextX, nextY]);
}
}
}
}
- ์ ์๋ํ์ต๋๋ค.
-
ํ์ธํธ ํด ์ฌ์ฉ ์ ์น ํด์ง ์์ญ ๊ฐ์ฅ์๋ฆฌ์ ์ด์ ์์ ์ ์ ํ์ ์ด ๋จ์์ต๋๋ค. ๋ค๋ง ์ด ํ์์ ๊ฐํฑํฐ ๊ฐ์ ์๋น์ค์์๋ ๋ฐ์ํ๊ณ ์์ด, ์ผ๋จ ์ต์ ํ ๋จ๊ณ์ ์ดํด๋ณด๋ ๊ฒ์ผ๋ก ๋ฏธ๋ค์ต๋๋ค.
-
๋ธ๋ผ์ฐ์ ์ฐฝ์์ ์๋์ ๊ฐ์ ์๋ด๋ฌธ์ด ๋ฐ์ํ๊ณ ์์ต๋๋ค.
Canvas2D: Multiple readback operations using getImageData are faster with the willReadFrequently attribute set to true. See: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently
- ์ต์ ํ์ ๋ํ ํ์ ์๋ ค์ฃผ๊ณ ์๋ ๊ฒ์ธ๋ฐ,
getImageData
๋ฉ์๋๋ฅผ ์์ฃผ ์ฌ์ฉํ๋ ํ๊ฒฝ์ผ ๊ฒฝ์ฐ, Canvas2D ์ธ์คํด์ค๋ฅผwillReadFrequently
์ต์ ๊ณผ ํจ๊ป ๊ฐ์ ธ์์ฃผ๋ฉด ์ฑ๋ฅ์ด ํฅ์๋ ์ ์๋ค๋ ๋ด์ฉ์ ๋๋ค. - ๋ธ๋ผ์ฐ์ ๋ canvas๊ฐ์ ๊ทธ๋ํฝ ์์๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก gpu๋ฅผ ์ฌ์ฉํด ๋ ๋๋งํฉ๋๋ค. ํ์ง๋ง ์ willReadFrequently ์ต์ ์ ์ฌ์ฉํ ๊ฒฝ์ฐ canvas๋ cpu๋ฅผ ์ ๊ทน์ ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
- cpu๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ gpu๋ก ๋ฐ์ดํฐ๋ฅผ ์ฎ๊ธฐ๋ ๊ณผ์ ์ด ์๋ต๋์ด ๋ ๋นจ๋ผ์ง ์ ์๋ค๋ ๊ฒ์ด์ต๋๋ค.
- ๊ทธ๋์
getImageData
,toDataURL
,toBlob
๋ฉ์๋๊ฐ ๋น๋ฒํ ๊ฒฝ์ฐ, ์ ์ค์ ์ ํตํด cpu ์ฒ๋ฆฌ๋ฅผ ๊ถ์ฅํ๋ค๋ ๋ด์ฉ์ด์์ต๋๋ค. - ์์ธํ ๋ด์ฉ์ ์๋ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด๋ณด๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ํ์ธํ ๊ธฐ๋ฅ์ด ๊ทธ๋ฆฌ ์์ฃผ ์ฐ์ผ๊น ์ถ์ด ์ฝ๋์๋ ๋ฐ๋ก ์ ์ฉํ์ง ์์์ต๋๋ค. ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ์ดํด๋ณผ ์์ ์ ๋๋ค.
- ์ต์ ํ์ ๋ํ ํ์ ์๋ ค์ฃผ๊ณ ์๋ ๊ฒ์ธ๋ฐ,
- 1. ๊ฐ๋ฐ ํ๊ฒฝ ์ธํ ๋ฐ ํ๋ก์ ํธ ๋ฌธ์ํ
- 2. ์ค์๊ฐ ํต์
- 3. ์ธํ๋ผ ๋ฐ CI/CD
- 4. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ด Canvas ๊ตฌํํ๊ธฐ
- 5. ์บ๋ฒ์ค ๋๊ธฐํ๋ฅผ ์ํ ์์ CRDT ๊ตฌํ๊ธฐ
-
6. ์ปดํฌ๋ํธ ํจํด๋ถํฐ ์น์์ผ๊น์ง, ํจ์จ์ ์ธ FE ์ค๊ณ
- ์ข์ ์ปดํฌ๋ํธ๋ ๋ฌด์์ธ๊ฐ? + Headless Pattern
- ํจ์จ์ ์ธ UI ์ปดํฌ๋ํธ ์คํ์ผ๋ง: Tailwind CSS + cn.ts
- Tailwind CSS๋ก ๋์์ธ ์์คํ ๋ฐ UI ์ปดํฌ๋ํธ ์ธํ
- ์น์์ผ ํด๋ผ์ด์ธํธ ๊ตฌํ๊ธฐ: React ํ๊ฒฝ์์ ํจ์จ์ ์ธ ์น์์ผ ์ํคํ ์ฒ
- ์น์์ผ ํด๋ผ์ด์ธํธ ์ฝ๋ ๋ถ์ ๋ฐ ๊ณต์
- 7. ํธ๋ฌ๋ธ ์ํ ๋ฐ ์ฑ๋ฅ/UX ๊ฐ์
- 1์ฃผ์ฐจ ๊ธฐ์ ๊ณต์
- 2์ฃผ์ฐจ ๋ฐ๋ชจ ๋ฐ์ด
- 3์ฃผ์ฐจ ๋ฐ๋ชจ ๋ฐ์ด
- 4์ฃผ์ฐจ ๋ฐ๋ชจ ๋ฐ์ด
- 5์ฃผ์ฐจ ๋ฐ๋ชจ ๋ฐ์ด
- WEEK 06 ์ฃผ๊ฐ ๊ณํ
- WEEK 06 ๋ฐ์ผ๋ฆฌ ์คํฌ๋ผ
- WEEK 06 ์ฃผ๊ฐ ํ๊ณ