-
Notifications
You must be signed in to change notification settings - Fork 7
๐ชต 4. ๋ณด๊ฐ๋ฒ ์ ์ฉ ๋ฐ ์ปค์ ๋ณด์
D.Joung edited this page Dec 5, 2024
·
1 revision
-
๋น ๋ฅด๊ฒ ๊ทธ๋ ธ์ ๋ ๋ชจ์๋ฆฌ ๋ถ๋ถ์์ ์ ์ด ๋๊ธฐ๋ ํ์์ด ๋ฐ์ํ์์ต๋๋ค.
-
ํ์ง๋ง ํฐ์น ์ด๋ฒคํธ์์๋ ๋ฐ์ํ์ง ์์์ต๋๋ค. (MouseEvent ํธ๋ฆฌ๊ฑฐ ์์๋ง ๋ฐ์)
- mousemove๋ ๋ง์ฐ์ค๊ฐ ์์ง์ผ ๋ ํธ๋ฆฌ๊ฑฐ๋์ง๋ง, ๋ชจ๋ ํฝ์ ์ด ์ด๋ฒคํธ์ ์ ๋ฌ๋์ง๋ ์์ต๋๋ค.
- mousemove ์ด๋ฒคํธ๋ ์ฌ์ฉ์ ๋๋ฐ์ด์ค์ Polling Rage(์ํ๋ง ๋น๋)์ ๋ฐ๋ผ ๋ฐ์ํฉ๋๋ค.
- ์ผ๋ฐ์ ์ธ ๋ง์ฐ์ค์ ํด๋ง ๋ ์ดํธ๋ 125Hz ๋๋ 1000Hz(๊ฒ์ด๋ฐ ๋ง์ฐ์ค)์ ๋๋ค.
- ๋ธ๋ผ์ฐ์ ๋ ํ๋์จ์ด์์ ๋ฐ์ํ ๋ชจ๋ ๋ง์ฐ์ค ์ด๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ์ง ์๊ณ , ์ด๋ฅผ ์ต์ ํํ์ฌ ์ํ๋งํ ์ขํ๋ง ์ ๋ฌํฉ๋๋ค.
- ๋ฐ๋ผ์, ๋น ๋ฅด๊ฒ ๊ทธ๋ฆด ๊ฒฝ์ฐ mousemove๋ ํ์ฌ ์ํ๋ง๊ณผ ๋ค์ ์ํ๋ง์ ์ค๊ฐ ํฝ์ ์ ๋์น ์๋ ์๊ฒ ๋๋ ๊ฒ์ ๋๋ค.
- ๋ง์ฐ์ค๊ฐ ๊ฐ์ฒด๋ฅผ ๋ฒ์ด๋ ๋ ํธ๋ฆฌ๊ฑฐ๋๋ mouseleave ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ์ขํ๊ฐ์ ์ถ๊ฐํ์ฌ, ๊ฒฝ๊ณ์ ๋ถ๋ถ์ ์ขํ๋ฅผ ๋ณด๊ฐํด์ค๋๋ค.
const { canvas, ctx } = getCanvasContext(mainCanvasRef);
const { x: drawX, y: drawY } = convertCoordinate(getDrawPoint(e, canvas));
ctx.lineTo(drawX, drawY);
ctx.stroke();
-
๋ง์ฐ์ค๊ฐ ํ๋ฉด ๋ฐ์ ๋ฒ์ด๋ ๋์ ์ขํ๋ฅผ ์ป์ด ๋ชจ์๋ฆฌ๊น์ง ์ ์ ๊ทธ์ ์ ์๋๋ก ํด์ฃผ๋ ๊ฒ์ ๋๋ค.
-
ํ์ง๋ง ํด๋น ์กฐ์น๋ก ๋ง๋ฌด๋ฆฌํ๊ธฐ์๋, touchEvent์์๋ ์ ์๋๋ถํฐ ์ ์๋ํ์๋ ์ง ๊ถ๊ธ์ฆ์ด ์๊ฒผ์ต๋๋ค.
์ touchEvent์์๋ ํด๋น ํ์์ด ์๋๊ฐ?
- ํฐ์น ๋๋ฐ์ด์ค๋ ๋ณดํต ์ ๋ฐํ ์ขํ ๊ฐ์ง๋ฅผ ์ํด ์ค๊ณ๋์ด์๋ค๊ณ ํ๋ค. ํ๋์จ์ด ์ฑ๋ฅ ์ฐจ์ด ๋ฌธ์ ๋ ์๋ค๋ ๋ป์ด๋ค.
- ํฐ์น ์ผ์๊ฐ ๋์คํ๋ ์ด ๋ฐ๋ก ์๋์ ์๊ธฐ ๋๋ฌธ์, ๋ฌผ๋ฆฌ์ ์ ๋ ฅ๊ณผ ํ๋ฉด์์ ์์น๊ฐ ๋ ์ง์ ์ ์ผ๋ก ์ฐ๊ฒฐ๋๋ค.
- ํฐ์น ์ด๋ฒคํธ๋ ์ฐ์์ ์ธ ์ขํ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฅํ๋๋ก ์ค๊ณ๋์๋ค.
- ์ ์ค์ณ ์ธ์, ์ค์์ดํ, ํ์น ์ค ๋ฑ์ ๊ธฐ๋ฅ์ด ์ค์ํ ํ๊ฒฝ์ด๋ฏ๋ก ํฐ์น์ ๋ ๋ฏผ๊ฐํ๊ฒ ์ค๊ณ๋์๋ค.
- ํฐ์น ์ด๋ฒคํธ๋ ์ฌ์ฉ์์ ์ฐ์์ ์ด๊ณ ์ง๊ด์ ์ธ ์
๋ ฅ ์ฒ๋ฆฌ๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํด ์ ์ญ์์ ์๋ํ๋๋ก ์ค๊ณ๋์๋ค.
- ์ฌ์ฉ์๊ฐ ํ๋ฉด์ ์ ์ดํ ๋์ ์ํ๋ฅผ ์ง์์ ์ผ๋ก ์ถ์ ํ๋ค.
- ํฐ์น๊ฐ ํน์ ์์์์ ์์ํด ์๊ฐ๋ฝ์ ์์ง์ฌ ๋ค๋ฅธ ์์๋ก ์ด๋ํ๊ฑฐ๋ ํ๋ฉด์ ๋ฒ์ด๋ฌ์ ๊ฒฝ์ฐ์๋, ์ด๋ฒคํธ๋ ํด๋น ํน์ ์์์ ๊ณ์ ์ ๋ฌ๋๋ค.
- canvas์์ ํฐ์น๊ฐ ์์๋์๋ค๋ฉด, cavas ๋ฐ์ผ๋ก ํฐ์น๊ฐ ์ด๋ํด๋ ํฐ์น์ ๊ด๋ จ๋ ์ด๋ฒคํธ๋ค์ canvas์์ ์ฒ๋ฆฌ๋๋ค๋ ๋ป์ด๋ค. (๋ค๋ฅธ ์์์ ํฐ์น ์ด๋ฒคํธ๋ค์ ๋ฌด์๋จ)
๋ฌธ์ ํด๊ฒฐ2. ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ document์ ๋ถ์ฐฉํ์ฌ ์ ๋ ฅ ์ขํ๊ฐ์ ์ ์ญ์์ ๊ด๋ฆฌ [์คํจ]
- ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ํน์ ์์์ ๋ถ์ฐฉํ์ฌ ์ฌ์ฉํ ๊ฒฝ์ฐ, ๋ง์ฐ์ค ์ปค์๊ฐ ๋น ๋ฅด๊ฒ ์์๋ฅผ ์ดํํ์ ๊ฒฝ์ฐ ์ด๋ฒคํธ๊ฐ์ ๋ฐ์ง ๋ชปํ ์ ์์์ต๋๋ค.
- ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ์ ์ญ ์์ค์ ํธ๋ค๋ฌ๋ฅผ ๋ถ์ฌ ์ ์ดํด์ฃผ์์ต๋๋ค.
const canvasEventHandlers: CanvasEventHandlers = {
mousedown: (e) => addDelegation(e, handleDrawStart),
mousemove: (e) => addDelegation(e, handleDrawMove),
mouseup: (e) => addDelegation(e, stopDrawing),
mouseleave: (e) => addDelegation(e, stopDrawing),
touchstart: (e) => addDelegation(e, handleDrawStart),
touchmove: (e) => addDelegation(e, handleDrawMove),
touchend: (e) => addDelegation(e, stopDrawing),
touchcancel: (e) => addDelegation(e, stopDrawing),
};
useEffect(() => {
for (const [event, handler] of Object.entries(canvasEventHandlers)) {
document.addEventListener(event, handler);
}
return () => {
for (const [event, handler] of Object.entries(canvasEventHandlers)) {
document.removeEventListener(event, handler);
}
};
}, [canvasEventHandlers]);
- ํ์ง๋ง ๊ฒฝ๊ณ์ ๋ถ๊ทผ์์ ์ ์ด ๋๊ธฐ๋ ์ด์๋ ํด๊ฒฐ๋์ง ์์์ต๋๋ค.
- ๋ํ, ์ ์ฒ๋ผ ๊ตฌํ ์ ๋ณ๊ฒฝํด์ผํ ๋ถ๋ถ์ด ๋ ์์ ๊ฒ ๊ฐ์, ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ๊ฒฌ๋์์ ๋ ๋ฆฌํฉํ ๋งํ์ฌ ๊ฐ์ ํ๋ ๋ฐฉํฅ์ด ๋ง์ ๊ฒ ๊ฐ๋ค๋ ๊ฒฐ๋ก ์ ์ด๋ฅด๋ ์ต๋๋ค.
- ๋ฐ๋ผ์ ์ฐ์ stopDrawing ๋ฉ์๋์ ๊ฒฝ๊ณ์ ์ขํ๋ฅผ ๋ณด๊ฐํ๋ ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ์ผ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
- ํ์ง๋ง ํด๋น ๋ฐฉ๋ฒ์ผ๋ก๋ ๋ธ๋ฌ์๊ฐ ํด๋ฆญํ ์ํ์์ ์บ๋ฒ์ค ๋ฐ์ผ๋ก ๋๊ฐ๋ค๊ฐ ๋์์์ ๋ ์ ์ด ์ด์ด์ง์ง ์์์ต๋๋ค.
- ๋ง์ฐ์ค ์ด๋ฒคํธ๊ฐ ์บ๋ฒ์ค์ ๋ถ์ด์์ผ๋ฉด, ๋ง์ฐ์ค๊ฐ ์บ๋ฒ์ค ๋ฐ์ผ๋ก ๋๊ฐ์ ๋์ ์ํ๋ฅผ ๋ชจ๋ํฐ๋ง ํ ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด์์ต๋๋ค.
- ๋ฐ๋ผ์ ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ์ด๋ฒคํธ๋ฅผ document์ ๋ถ์ฌ ์ ์ญ์์ ๊ด๋ฆฌํด์ผ ํ ๊ฒ์ด๋ฉฐ, ํด๋น ํ์์ฑ์ด ์๊ฒผ์ ๋ ์๋ํ ์์ ์ ๋๋ค.
- ์ ์ ๊ทธ๋ฆด ๋ ๋ถ๋๋ฝ๊ฒ ๊ทธ๋ ค์ง์ง ์๋ ์ด์๊ฐ ์์์ต๋๋ค.
- ์ฒ์์๋ ํฝ์ ์ด ๊นจ์ง๋ ํ์์ธ ์ค ์๊ณ ์ํฐ ์จ๋ฆฌ์ด์ฑ์ ์ ์ฉํ์์ง๋ง, ์ดํ ๊ทธ๋ฆด ๋ ์ ์ด ๊ตด๊ณก์ง๋ ์ด์์ ๊ฐ๊น๋ค๋ ์ฌ์ค์ ๊นจ๋ฌ์์ต๋๋ค.
- ์๋๋ ์์๋๋ก ํ ์๋น์ค์ธ ๊ฐํฑํฐ์
๋ถ๋๋ฌ์ด ์
, ์ฐ๋ฆฌ ์๋น์ค์๊ฐ์ง๋ ์
์ด๋ฏธ์ง์ ๋๋ค.
๋ง์ฐ์ค ํด๋ง ๋ ์ดํธ(Polling Rate)๋?
- ํด๋ง ๋ ์ดํธ๋ ํน์ ๊ธฐ๊ธฐ์์ PC๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ์ฃผ๊ธฐ์ ๋๋ค. ์บ๋ฒ์ค ์ํฉ์์๋ ๋ง์ฐ์ค ํน์ ํฐ์น ์คํฌ๋ฆฐ์ด PC๋ก ์ขํ๋ฅผ ์ ๋ฌํ๋ ๋น๋๊ฐ ๋ ๊ฒ์ ๋๋ค.
- ๋จ์๋ Hz(ํค๋ฅด์ธ )๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด ๋น ๋ช ๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ์ง๋ฅผ ๋ํ๋ด๋ ์์น์ ๋๋ค.
- ์ผ๋ฐ์ ์ธ ํด๋ง ๋ ์ดํธ ๋จ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- 125Hz: ์ด๋น 125๋ฒ ๋ฐ์ดํฐ ์ ์ก (8ms ๊ฐ๊ฒฉ)
- 250Hz: ์ด๋น 250๋ฒ ๋ฐ์ดํฐ ์ ์ก (4ms ๊ฐ๊ฒฉ)
- 500Hz: ์ด๋น 500๋ฒ ๋ฐ์ดํฐ ์ ์ก (2ms ๊ฐ๊ฒฉ)
- 1000Hz: ์ด๋น 1000๋ฒ ๋ฐ์ดํฐ ์ ์ก (1ms ๊ฐ๊ฒฉ)
- ํ์ง๋ง! ์ผ๋ฐ์ ์ธ ๋ธ๋ผ์ฐ์ ์ ๋ง์ฐ์ค ์ด๋ฒคํธ๋ ์์ ๊ฐ์ ํ๋์จ์ด์ ํด๋ง ๋ ์ดํธ์ ์๋ฒฝํ ๋๊ธฐํ๋์ง ์์ต๋๋ค.
๋ธ๋ผ์ฐ์ ๋ง์ฐ์ค ์ด๋ฒคํธ ๋ฐ์ ๋น๋
- ๋ธ๋ผ์ฐ์ ๋ง์ฐ์ค ์ด๋ฒคํธ์ ๋ฐ์ ๋น๋๋ ํ๋ฉด ์ฌ์ ๋น๋(Refresh Rate)์ ๋ ๋ฆฝ์ ์ผ๋ก ์๋ํฉ๋๋ค.
- ๋๋ถ๋ถ์ ๋์คํ๋ ์ด๋ 60Hz(16.67ms ๊ฐ๊ฒฉ)๋ก ๋์ํฉ๋๋ค.
- ๋ธ๋ผ์ฐ์ ๋ ์์คํ ์ด๋ฒคํธ ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ง์ฐ์ค ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค..
- ํด๋ง ๋ ์ดํธ ๊ฐ๊ฒฉ์ผ๋ก ๋ง์ฐ์ค๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ฉด, ๋ธ๋ผ์ฐ์ ๋ ์ด๋ฅผ ํ ๋๋ก mouseEvent๋ฅผ ๋ฐ์ ์ํต๋๋ค.
- ์ฆ, ๋ง์ฐ์ค ์ด๋ฒคํธ ๋ฐ์ ๋น๋๋ ํด๋ง ๋ ์ดํธ์ ๊ด๋ จ์ด ์์ต๋๋ค.
Polling Rate์ Refresh Rate ๊ฐ์ ๊ด๊ณ
- ํ์ง๋ง, Polling Rate๊ฐ ์๋ฌด๋ฆฌ ๋์๋ Refrash Rate๊ฐ 60Hz๋ฉด ํด๋ง ๋ ์ดํธ ๋ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ์ํ๋ง๋์ง๋ ๋ชปํฉ๋๋ค.
- ๋ง์ฐ์ค๊ฐ 1์ด์ 150๋ฒ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋๋ผ๋, ๋ธ๋ผ์ฐ์ ๋ ์ด ๋ฐ์ดํฐ๋ฅผ 1์ด์ 60๋ฒ ๋ง ํ์ธํ์ฌ ๋ ๋๋ง ํ ์ ์๋ ๊ฒ์ ๋๋ค.
- ๋ธ๋ผ์ฐ์ ๋ 1/60์ด๋ง๋ค ๋ง์ฐ์ค๊ฐ ๋ณด๋ธ ๋ฐ์ดํฐ ์ค ๊ฐ์ฅ ์ต์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ๊ฐ๊ฒ ๋ฉ๋๋ค.
- ์ด๋ ๊ฒ ๊ฐ์ ธ์ค๊ฒ ๋ ๋ฐ์ดํฐ๋ฅผ ์ํ๋ง๋ ๋ฐ์ดํฐ๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
- ๋ง์ฐ์ค ์ด๋ฒคํธ๋ ํ๋ฉด ๊ฐฑ์ ์ฃผ๊ธฐ์๋ ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐ์ํ ์ ์์ต๋๋ค. (๋ ๋ง์ ์๋ ์์.)
canvas.width = canvas.clientWidth * window.devicePixelRatio;
canvas.height = canvas.clientHeight * window.devicePixelRatio;
ctx.imageSmoothingEnabled = true;
...
...
const convertCoordinate = ({ x, y }: Point): Point => {
return { x: Math.floor(x * coordinateScale.current) + 0.5, y: Math.floor(y * coordinateScale.current) + 0.5 };
};
...
...
const ctx = canvas.getContext('2d', { willReadFrequently: true });
- ํํ ์ถ์ฒํ๋ ์ํฐ ์จ๋ฆฌ์ด์ฑ ๋ฐฉ๋ฒ์ ์ ์ฉํด๋ณด์์ง๋ง ํฐ ์ฐจ์ด๋ ์์์ต๋๋ค.
- ๋ฌด์๋ณด๋ค, ์์์ ์ ๋ฆฌํ ๊ฒ ์ฒ๋ผ ์ ์ด ๊ฐ์ง๋ ์ด์๋ ์ํฐ ์จ๋ฆฌ์ด์ฑ๊ณผ๋ ๊ด๋ จ์ด ์์ต๋๋ค.
useEffect(() => {
let lastTime: DOMHighResTimeStamp = 0;
const drawAnimation = (timestemp: DOMHighResTimeStamp) => {
if (timestemp - lastTime > 16) {
if (currentDrawingRef.current) drawData(currentDrawingRef.current);
lastTime = timestemp;
}
requestAnimationFrame(drawAnimation);
};
const aniId = requestAnimationFrame(drawAnimation);
return () => {
if (aniId) cancelAnimationFrame(aniId);
};
}, []);
- requestAnimationFrame ์ธ์๋ก ๋์ด์ค๋ timestamp ๊ฐ์ ์ด์ฉํด
16ms
๊ฐ๊ฒฉ์ผ๋ก ๊ทธ๋ฆฌ๊ธฐ ํจ์๋ฅผ ์คํํด๋ณด์์ต๋๋ค. - ํ์ง๋ง requestAnimationFrame์ timestamp๋ ๋ธ๋ผ์ฐ์ ์ฑ๋ฅ์ ๋ฐ๋ผ ๊ฐ๊ฒฉ์ด ๋ฌ๋ผ์ง ์ ์๊ธฐ ๋๋ฌธ์,
performance.now()
๋ฅผ ์ฐ๋ ๊ฒ์ด ์ ํํ์ต๋๋ค. - ๊ฒฐ๊ณผ์ ์ผ๋ก ์ ์๋๋ก ํฌ๊ฒ ๋ฌ๋ผ์ง๋ ์ ์ ์์๊ณ , ์ ์ด ๊ตด๊ณก์ง๋ ์ด์๋ ์ ๊ณผ ์ ์ฌ์ด์ ๊ฐ์ด ์ง๋ ํ์์ผ๋ก ๋ ๋๋ง ์ฑ๋ฅ๊ณผ๋ ํฌ๊ฒ ์๊ด์ด ์์์ต๋๋ค.
- ์ ์ด๋ฏธ์ง์์ ํ์ธํ ์ ์๋ฏ์ด, ๋ง์ฐ์ค์์ ์ํ๋ง๋ ํฌ์ธํธ ๊ธฐ์ค์ผ๋ก ๊ตด๊ณก์ด ์ ธ์์ต๋๋ค.
- ์ฆ, ํด๋น ๋ฌธ์ ๋ ์ ์ด ์ฐํ๋ ๊ฐ๊ฒฉ(Event Sampling Rate)์ ์กฐ์ ํ๊ฑฐ๋, ๋ณด๊ฐ(Interpolation) ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ํด๊ฒฐํด์ผ ํ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ต๋๋ค.
- ์คํ๋ผ์ธ์ด๋ ๊ธฐ์ค์ ๊ณผ ์ ์ด์ ์ ํตํด ๊ทธ๋ ค์ง๋ ๊ณก์ ์ ๋ปํฉ๋๋ค. ์คํ๋ผ์ธ ๊ทธ๋ฆฌ๊ธฐ๋ ์ขํ ๋ผ์ธ์ ํจ์ ๋ชจ์์ ๋ฐ๋ผ 1์ฐจ, 2์ฐจ, 3์ฐจ ๋ฑ์ผ๋ก ๋๋ฉ๋๋ค.
- ๋ถ๋๋ฌ์ด ๊ณก์ ์ ๊ณ์ฐํ๋ ๊ฒ์ ๊ฒฐ๊ตญ ์ฐํ ์ ๋ค์ด ์ด๋ค ๋ฐฉ์ ์ ๊ทธ๋ํ ์์ ์๋ ์ง๋ฅผ ๊ณ์ฐํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ 1์ฐจ ์คํ๋ผ์ธ์ ๋ ๊ฐ์ ์ ๋ง ์์ผ๋ฉด ๊ตฌํํ ์ ์๊ณ , 2์ฐจ ์คํ๋ผ์ธ์ ์ต์ 3๊ฐ์ ์ ์ด ํ์ํ๊ฒ ๋ฉ๋๋ค. 3์ฐจ ์คํ๋ผ์ธ์ 4๊ฐ์ ์ ์ด ์์ด์ผ ๊ทธ๋ํ ๋ฐฉ์ ์์ ๊ตฌํ ์ ์์ต๋๋ค.
- ์์ ๋ฐฉ์์ผ๋ก ๊ธฐ์ค์ ๋ค์ด ์ด์ด์ง๋ ๋ฐฉ์ ์์ ๊ตฌํ ํ, ์คํ๋ผ์ธ์ ๋ชจ์์ ํ์ ํ๊ธฐ ์ํด ํ์ํ ๊ฒ์ด ์ ์ด์ ์
๋๋ค.
- ์ ์ด์ ์ ๊ณก์ ๋ฐฉ์ ์์ ๋ฏธ๋ถํ์ฌ 1์ฐจ ๋ํจ์, 2์ฐจ ๋ํจ์๋ฅผ ํ์ฉํด ๊ณ์ฐํฉ๋๋ค. 1์ฐจ ๋ํจ์๋ x์ขํ์ ๋ฐ๋ฅธ ๊ธฐ์ธ๊ธฐ๋ฅผ, **2์ฐจ ๋ํจ์๋ ํน์ ์ ์์์ ๊ธฐ์ธ๊ธฐ ๋ณํ๋(๊ณก๋ฅ )**์ ์๋ฏธํฉ๋๋ค.
- ์ฐจ์๊ฐ ๋์์ง ์๋ก ๋ํจ์๋ค์ ๊ตฌ์กฐ๋ ๋ ๋ณต์กํด์ง๊ณ , ๋ค์ํ ๊ณก๋ฅ ์ ๊ตฌํํ ์ ์๊ฒ ๋ฉ๋๋ค.
- Context2D ์ lineTo๊ฐ 1์ฐจ ์คํ๋ผ์ธ์ ๊ทธ๋ฆด ์ ์๊ฒ ํด์ฃผ๋ ๋ฉ์๋์ ๋๋ค.
- quadraticCurveTo์ bezierCurvetTo ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๊ฐ 2์ฐจ ์คํ๋ผ์ธ, 3์ฐจ ์คํ๋ผ์ธ์ ๊ทธ๋ฆด ์ ์์ต๋๋ค.
- canvas api์์ quadratic ์คํ๋ผ์ธ์ ๊ทธ๋ ค์ฃผ๋ ๋ฉ์๋์ ๋๋ค.
- quadraticCurveTo(cp1x, cp1y, x, y)
- cp๋ ์ ์ด์ , x ๋ฐ y๋ ๋ง์ง๋ง์ ์ฐํ ์ ์ ์๋ฏธํฉ๋๋ค. quadratic ์คํ๋ผ์ธ์ ์ต์ 3๊ฐ์ ์ ์ด ์์ด์ผ ๊ณก์ ์ ๊ทธ๋ฆด ์ ์์ผ๋ฏ๋ก, ์ 3๊ฐ์ผ ๋ ๋ถํฐ ๊ณก์ ์ ๊ทธ๋ฆด ์ ์๋๋ก ํด์ผํฉ๋๋ค.
- ์ฒซ ๋ฒ์งธ ์ ๊ณผ ๋ง์ง๋ง ์ ์ฌ์ด์ ์ ๋ค์
์ ์ด์
์ผ๋ก ์ผ์ ๊ณก์ ์ ๊ทธ๋ ค๋๊ฐ๋ ๋ฐฉ์์ ์ฌ์ฉํ์ต๋๋ค.
const drawSmoothLine = (drawingData: DrawingData, canvasRef: RefObject<HTMLCanvasElement>) => {
const { ctx } = getCanvasContext(canvasRef);
if (!currentDrawingRef.current) return;
const { points } = drawingData;
if (currentDrawingRef.current.points.length < 2) return;
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length - 1; i++) {
const midPoint = {
x: (points[i].x + points[i + 1].x) / 2,
y: (points[i].y + points[i + 1].y) / 2,
};
ctx.quadraticCurveTo(points[i].x, points[i].y, midPoint.x, midPoint.y);
}
// ๋ง์ง๋ง ์ ์ฐ๊ฒฐ
ctx.stroke();
};
- ํ์ง๋ง ์ ๋ฐฉ์์ ์ง์ฐ์ด ๋ง์ด ๋ฐ์ํด ์ถํ ๋์ ๊ณผ์ ๋ก ๋จ๊ฒจ๋๊ฒ ๋์์ต๋๋ค.
- 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 ์ฃผ๊ฐ ํ๊ณ