๋ฉด์ ์ ๋ค๋๋ค ๋ณด๋ฉด ์๋นํ ๋ง์ ๋ถ๋ค์ด pdf๋ก ๋ ์ด๋ ฅ์์ ์์ดํจ๋๋ก ๋ฉ๋ชจ๋ฅผ ํ์๋ฉด์ ์งํํ์ จ๋๊ฑธ๋ก ๊ธฐ์ตํ๋ค.
์ต๊ทผ ์ด๋ ฅ์๋ฅผ ํํ์ด์ง๋ก ์ง์ ๊พธ๋ฉฐ ๋ฐฐํฌ๋ฅผ ํ๋ ค๋ ๋์ค์ ์์ ๊ธฐ์ต๋ค์ด ๋ ์ฌ๋ผ์
(๊ทธ๋ฆฌ๊ณ ๋ง์นจ ์ฝ๊ณ ์ฌ๋ฐ์ ๊ฒ ๊ฐ์์)
๋ฉ๋ชจํ๋ ๊ธฐ๋ฅ์ ์ง์ ๋ง๋ค์ด๋ณด๋ฉด ์ข๊ฒ ๋ค๋ ๋ง์์ ๋จน๊ณ ๊ฐ๋ฐ์ ์ฐฉ์ํ๊ฒ ๋์๋ค.
๊ทธ๋ฅ ๋จ์ํ๊ฒ ๊ธฐ๋ฅ๋ง ๊ตฌํํ๋ค๊ณ ํ๋ฉด ๋ณ ๊ฒ ์๋๋ผ๊ณ ์คํํ๋๋ฐ, ์จ๊ฐ ์ค์ ์ฌ์ฉ ํ ์คํธ๋ฅผ ๊ฒช์ผ๋ฉฐ ์ผ์ด์ค๋ฅผ ํ์ธํด๋ณด๋ฉด ์ ๋ง ์ค๋ง๊ฐ์ง ์๋ฌ๋ฅผ ๋ค ๋ง๋๊ฒ ๋์๋ค. ๊ทธ๋์ ๋ ๋ง๋ค ๊ทธ ์๋ฌ๋ค์ ํด๊ฒฐํ๋๋ผ๊ณ ์ ์ ์ด ์์๋ค.
๊ฐ์ธ์ ์ผ๋ก ๋ง์ ์ฐ์ฌ๊ณก์ ์ ๊ฒช์ ํ ์ด ํ๋ก์ ํธ์ด๊ณ , ๊นจ๋ซ๋ ์ ์ด ์์ด ์ด๋ฅผ ๊ธฐ๋ก์ผ๋ก ๋จ๊ธฐ๋ ค๊ณ ํ๋ค.
์์ง๋ ๋ง์ ๋ถ๋ถ ๊ฐ์ ์ค์ด์ง๋ง ๊ถ๊ธํ์ ๋ถ๋ค์ "์ค๋์์จ์ ๋ ์ฅฌ๋ฉ ํ์ด์ง" ๋ "๋ ์ฅฌ๋ฉ ์์ค์ฝ๋" ๋ฅผ ์ฐธ์กฐํด์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค.
์์ ์ ์ํฐ๋ ํ๋ฆฌ์จ๋ณด๋ฉ ์ธํด์ญ์ ์ฐธ์ฌํ์ ๋ ๊ฐ์ธ๊ณผ์ ์ค ํ๋์๋ ๋๋๊ทธ ๋ธ๋ก ์์ญ ๋ง๋ค๊ธฐ ์์ ์บ๋ฒ์ค๋ฅผ ์ฌ์ฉํด๋ดค๋ ๊ธฐ์ต์ด ์๋ ํฐ๋ผ, ํด๋น ๋๋ก์ ๊ธฐ๋ฅ์ด ์บ๋ฒ์ค์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ด์ฉํด์ ๊ตฌํํ ์ ์์์ ์ง์ํ๊ณ ์์๋ค.
์บ๋ฒ์ค์์ 2d ๊ทธ๋ํฝ ๋์์ธ์ ๊ทธ๋ฆฌ๊ธฐ ์ํด์๋ ์บ๋ฒ์ค element์์ getContext('2d')
๋ฅผ ํตํด ์ป์ ์ ์๋ ์ปจํ
์คํธ ์ธ์คํด์ค ๋ด์ ๋ฉ์๋๋ค์ ์ ์ ์ด ํ์ฉํ๋ฉด ๊ฐ๋ฅํ๋ค.
const context = canvas.getContext('2d');
context.beginPath = ๋๋ก์์ ์์์ ์๋ฆฌ๋ ํจ์
context.moveTo(x,y) = ๋๋ก์์ ์์ ์ขํ๋ฅผ ์ค์ ํ๋ ํจ์
context.lineTo(x,y) = ํน์ ์ขํ๊น์ง ๋๋ก์ ๊ฒฝ๋ก๋ฅผ ๋ง๋๋ ํจ์
context.stroke = ๋ง๋ค์ด์ง ๋๋ก์ ๊ฒฝ๋ก์ ์ค์ ํฝ์
์ ์ ์ฉ์์ผ ์บ๋ฒ์ค์ ๋ํ๋ด๊ฒ ๋ง๋๋ ํจ์.
์ฆ ์บ๋ฒ์ค์ ๋ผ์ธ ํ๋๋ฅผ ๊ทธ๋ฆฌ๋ ค๋ฉด beginPath => moveTo => lineTo => stroke ์์ผ๋ก ์งํํ๋ฉด ๋๋ค.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง ๋ด์ฉ์ ์บ๋ฒ์ค element ๋ด์ ํฝ์ ๋ก ๋จ์์๊ฒ ๋๋ค.
๋ง์ฝ ์บ๋ฒ์ค ๋ด์ ์ง์ ๋ pixel๊ฐ๋ค์ ์ด๊ธฐํํ๊ณ ์ถ๋ค๋ฉด context.clearRect
๋ฅผ ์ด์ฉํ๋ฉด ๋๋ค. ๋ค์ด๋ฐ์์ ํ์ธํ ์ ์๋ฏ์ด ํธ์ถ์ ํ๋ฉด ์ธ์๋ก ์ ๋ฌ๋๋ ์์ญ๋งํผ์ ํฝ์
์ ์ญ์ ํ๋ค.
์์ ๋ด์ฉ๋ง ๋ด์๋ ์ฐธ์ผ๋ก Easyํ๊ธฐ ๊ทธ์ง์๋ ๋ด์ฉ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ์ค์ ๋ก๋ ์ธํฐ๋ท์ ๋ธ๋ก๊น ๋์ด์๋ ๋ด์ฉ๋ค์ ๋ณด๋ฉด ์ฌ๊ธฐ๊น์ง์ ๋ด์ฉ์ด ๋ง๋ค.
๊ทธ๋ฐ๋ฐ, ๋ฌธ์ ๋ ๋ชจ๋ฐ์ผ๊ณผ ๊ฐ์ ํ๊ฒฝ์์ ์ฌ์ฉํ ๊ฒฝ์ฐ๋ ํฐ์น๊ฐ ์๋ ํ ํด์ ์ด์ฉํ๊ฑฐ๋, ํน์ ์น์ฌ์ดํธ์ธ๋ฐ ๋ฐ์ํ์ผ๋ก ํด๋ผ์ด์ธํธ ์ฌ์ด์ฆ๋ฅผ ์ค์ธ๋ค๊ฑฐ๋ ํ๋ ์ฌ์ฉ์ ์ธก๋ฉด์ ์์ธ ์ผ์ด์ค๋ค์์ ๋ฐ์ํ์๋ค.
๊ฒ๋ค๊ฐ ๋ด๊ฐ ์ํ๋ ๊ฒ์ ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ๋ค๊ฐ ์ฌ์ฉ์๊ฐ ์ด๊ฒ์ ๋ค์ ๋ถ๋ฌ์ฌ ์ ์๋๋ก ํ๋ ๊ฒ์ด์๋๋ฐ, ๋น์ฐํ ๋ณ ์๊ฐ์์ด ์ localstorage ์ธ๊ฑฐ์ผ
ํ๊ณ ์์ผํ๊ฒ Serializing ํด์ ์ ๋ฌํ๋ค๊ฐ ์น์ด ํฐ์ง๋ ์ผ์ด์ค๋ ์์๋ค.
์ด ํ๋ก์ ํธ๋ฅผ ์งํํ๊ธฐ ์ ๊น์ง์ ๋์๊ฒ ์ธ์ ๋ ๋ก์ปฌ ์ ์ ์๊ฒ ๋ฌด์ธ๊ฐ๋ฅผ ์ ์ฅ์ํค๋ ค๋ฉด ๋น์ฐํ ํํ๋ ์ ํ์ง๋ "๋ก์ปฌ ์คํ ๋ฆฌ์ง" ์์๋ค.
๊ทธ๋ฐ๋ฐ, ์ด๋ฒ์ ์บ๋ฒ์ค ์ด๋ฏธ์ง๋ฅผ ๋ก์ปฌ์คํ ๋ฆฌ์ง์ ์ง์ด๋ฃ์ผ๋ ค๋ค๊ฐ ์น์ด ํฐ์ง๋ ์ํฉ์ด ๋ฐ์ํ๋ค.
์คํ ๋ฆฌ์ง ์ฉ๋์ด ๋์น ๊ฒฝ์ฐ ์ฝ๊ฒ ๋ง๋๊ฒ ๋๋ QuataExceeded ์๋ฌ์ ์์
์ฒ์์๋ ๊ทธ๋ฅ ์บ๋ฒ์ค์์ ์ถ์ถ๋ ์ด๋ฏธ์ง ๊ฐ์ฒด ๊ทธ ์์ฒด๋ฅผ ์ง๋ ฌํํ์ฌ ๋ฃ์๋ ๊ฒ์ด ๋ฌธ์ ๋ผ๊ณ ์๊ฐํ๋ค.
์๋ํ๋ฉด ์ด๋ฏธ์ง ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํํด๋ ์ด๋ฏธ ๊ทธ ํฌ๊ธฐ๊ฐ ์ต์ 5mb
๋ฅผ ๋์ด๊ฐ๊ธฐ ๋๋ฌธ์ด์๋ค.
๋จ์ํ๊ฒ ์ ํ๋๋ง ์ฐ์ด๋ ์์ฑ๋๋ ์บ๋ฒ์ค ์ด๋ฏธ์ง๊ฐ 2๊ฐ๋ง ๋์ด๋ ์ด๋ฏธ localStroage๋ ์ฉ๋ ์ด๊ณผ๋ฅผ ์ผ์ผํค๋ฉฐ ์๋ฌ๋ฅผ ๋ฐ์์ํจ๋ค.
๊ทธ๋ฐ๋ค๊ณ ๊ฐ์ธ ๋ฉ๋ชจ ์์คํ ์ ์ํด์ ์๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ตฌ์ถํ๋ ๊ฒ์ ๊ณผํ ํธ๋ ์ด๋๋ผ๊ณ ์๊ฐํ๋ค.
์ค๋ น AWS๋ก ์๋ฒ๋ง๋ค๊ณ RDS์๋ค๊ฐ ๋ฉ๋ชจ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค๊ณ ํด๋ ๋ฌธ์ ๋ค. ๊ณผ์ฐ ์ด๊ฒ Production Level์ ๊ณ ๋ คํ๋ค๋ฉด ๋ง๋ ๊ตฌํ์ผ๊น
๋ต์ ์ ๋ ์๋๋ค์๋ค. ํ ์ฌ๋์ด ๋ฉ๋ชจ๋ฅผ ๋ช๋ฒ ํ ๊ทธ์๊ฒ๋ง์ผ๋ก๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๋๊ฒ ๋ช์ญ mb๋ผ๋ฉด ์ ์ ๊ฐ ์๋ฐฑ, ์์ฒ, ์๋ง์ด ๋๋ ์๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๋ ๋ฐ์ดํฐ์ ์์ ๊ธฐํ๊ธ์์ ์ผ๋ก ๋์ด๋ ๊ฒ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ๋ด ๋๋ DB ์ ์ง๋น๋ก ๋ ์๊ฐ๊ฒ์ด๋ค
๋๋ ์ด๋ป๊ฒ๋ ๊ฐ์ธ์ ๋ฉ๋ชจ ๋ฐ์ดํฐ๋ ๊ฐ๋ณ ํด๋ผ์ด์ธํธ๊ฐ ์์งํ๊ณ ์๊ธฐ๋ฅผ ๋ฐ๋๋ค.
๋ง์น ์ฟ ํค์ฒ๋ผ, ๊ฐ๋ณ์ ์ผ๋ก๋ง ์๋ณ ๊ฐ๋ฅํ๊ณ ์ฌ์ฉ๋ ๋ฐ์ดํฐ๊ฐ ๊ตณ์ด ์๋ฒ์ ์ธ์ ์ด๋ DB์ ์ ์ฅ๋๋ ๊ฒ์ ์ณ์ง ๋ชปํ๋ค๊ณ ์๊ฐํ๋ค.
๊ทธ๋์ ํด๋ผ์ด์ธํธ๋จ์์ ์ฌ์ฉํ ์ ์ฅ์๋ฅผ ์กฐ๊ธ ๋ ์ฐพ์๋ณด๋ ์น ์คํ ๋ฆฌ์ง๋ก indexedDB๋ผ๋ ์กด์ฌ๊ฐ ์๋ค๋ ์ฌ์ค์ ์๊ฒ ๋์๋ค.
indexedDB์ ๋ํ ์ฌ์ฉ๋ฐฉ๋ฒ์ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ indexedDB ํํ ๋ฆฌ์ผ ์์ ์์ธํ๊ฒ ์ค๋ช ํด์ฃผ๊ณ ์๋ค. ์ด๋ฒ์๋ ๊ฐ์ ์ ์ ๋ํ ๋ด์ฉ์ ์ฃผ์ ๋ก ์ ์ ๊ฒ์ด๊ธฐ์ indexedDB์ ๋ํ ์ฌ์ฉ๋ฐฉ์์ ๊ธฐ๋ก์ ์ถํ ๋จ๊ธฐ๊ณ ๋งํฌ๋ก ๋์ฒดํ๋ ค ํ๋ค.
๊ธฐ๋ณธ์ ์ธ ์ปจ์ ๋ง ๋ค์ ์๊ธฐํด๋ณด์๋ฉด
- indexedDB๋ ํด๋ผ์ด์ธํธ์ธก์์ ์ ๊ณตํ๋ ์คํ ๋ฆฌ์ง API์ด๋ค.
- ์ ์ฅ ๊ณต๊ฐ์ ๋ธ๋ผ์ฐ์ ๋ง๋ค ์ฐจ์ด๊ฐ ์์ง๋ง ๋ณดํต HDD์ 50% ์ด์ ์ ์ฅ์ด ๊ฐ๋ฅํ๋ค.
- ๊ฑฐ์ ๋ชจ๋ ๋ฐ์ดํฐ ํ์ ์ ์ ์ฅํ ์ ์๋ค. (key - value ํํ๋ก ๊ด๋ฆฌ๋๋ค)
- Transaction์ด๋ผ๋ DBํต์ ์ ์ํ ์ธ์คํด์ค์ ๋ฉ์๋๋ค์ ํ์ฉํด ๋น๋๊ธฐ์ ์ผ๋ก CRUD ์์ ์ ํ๋ค.
์ด ์น ์คํ ๋ฆฌ์ง๋ฅผ ํ์ฉํ๋ฉด ์ผ๋ง๋ ์ง ์์ ๋กญ๊ฒ ์์์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅ์ํฌ ์ ์์๋ค.
(์ปดํจํฐ์ ์์ฌ์ฉ๋์ ๋๊ธธ ์๋ ์์ง๋ง, ๊ทธ ์ ๊น์ง๋ผ๋ฉด ์ ์ฅ ๊ฐ๋ฅ! ๊ทธ๋ฆฌ๊ณ ์์ฌ ์ฉ๋๋ navigator API๋ฅผ ํ์ฉํ์ฌ ์ ์ฅํ๊ธฐ ์ ๋ฏธ๋ฆฌ ํธ๋ค๋ง์ด ๊ฐ๋ฅํ๋ค.)
๊ทธ๋์ ์ฒ์์๋ indexedDB์๋ค๊ฐ ์ด๋ฏธ์ง ์ธ์คํด์ค ๊ทธ ์์ฒด๋ฅผ ์ง์ด๋ฃ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ์๋ค.
๊ทธ๋ฐ๋ฐ, ๊ทธ๊ฒ ๊ณผ์ฐ ๊ด์ฐฎ์ ํ๋์ผ๊น ํ๋ ์๋ฌธ์ด ๋ด indexedDB ์คํ ๋ฆฌ์ง๋ฅผ ๋ฐ๋ผ๋ณด๋ฉด์ ๋ค๊ฒ ๋์๋ค.
์ด๋ฒ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์๋, ๊ฐ๊ฐ์ธ์ ์ปดํจํฐ์ ์ ์ฅ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ด์ํค๋ ๊ฒ์ด ๋๋ค. ๊ทธ๋ฌ๋ ๋ญ ๋ช๋ฐฑ๋ฉ๊ฐ๋ฐ์ดํธ์ ๋์ผ... ๋ผ๊ณ ์๊ฐํ๊ณ ๊ทธ๋ฅ ์ด๋ฏธ์ง ๋ฐ์ดํฐ ํต์งธ๋ก ๋ค ์ ์ฅ์ํค๊ฒ ๋ง๋ค๋ฉด ๊ฐ๋ฐํ๋ ์
์ฅ์์ ๋ก์ง์ ํธํด์ง๊ฒ ์ง๋ง, ์ฌ์ฉ์๋ ๋ถํ์ํ๊ฒ ๊ฐ๊ณ ์ถ์ง๋ ์์ ๋ฐ์ดํฐ๋ฅผ ๊ณต๊ฐ์ ์ฐจ์งํ๋ฉด์ ๊ฐ๊ณ ์์ด์ผ ํ๋ค.
๊ฑฐ๊ธฐ๋ค๊ฐ ์ ์ฅ๋ง ํ๊ณ ๋๋ ๋ฌธ์ ๊ฐ ์๋์๋ค. ์ฌ์ฉ์๊ฐ ๋ง์ฝ ํ์ 200๋ฒ ๊ทธ์๋ค๊ณ ๊ฐ์ ํ์ ๋, ๋ค์ ๋์์ค๋ฉด ์ด 200๋ฒ์ ๋ํ ๋ชจ๋ ์ด๋ฏธ์ง๋ฅผ canvas์ ๊ทธ๋ ค๋ด์ผ ํ๋ค. ์ด๋ ์์ฒญ๋ ๋ฒ๋ฒ ์์ ์ ๋ฐํ์ฌ UX์ ๊ทน๋๋ก ์ ์ํฅ์ ๋ฏธ์ณค๋ค.
๊ทธ๋์ ์ต๋ํ ์ต์ ํ์ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๊ณ ์ ๊ณ ๋ฏผ์ ํ๊ฒ ๋์๊ณ , ์๋์ ๊ฐ์ ๊ฒฐ๋ก ์ ์ป๊ฒ ๋์๋ค.
์ฐ์ 1๋ฒ์ ๋ํด์๋ canvas์์ ์์ฒด์ ์ผ๋ก ์์ ์ ๋ฐ์ดํฐ๋ฅผ dataURL๋ก ๋ณํํด ๋ฐํํ๋ ๋ฉ์๋ canvas.toDataURL
์ ์ฌ์ฉํ๋ฉด ๊ฐ๋จํ๊ฒ ํด๊ฒฐ๋๋ค.
dataURL์ด๋ ํน์ ๋ฐ์ด๋๋ฆฌ ํ์ผ์ data์ ๋์ฌ๊ฐ ๋ถ๋ ์คํธ๋ง ๊ฐ์ผ๋ก ๋ณํํ ๊ฐ์ด๋ค.
๊ตฌ์กฐ์ ์ผ๋ก data:MIMEํ์ ;์ธ์ฝ๋ฉ๋ฐฉ์, ๋ณํ์ฒ๋ฆฌ๋ ์คํธ๋ง๊ฐ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
๊ทธ๋์ ๋ฉ๋ชจ ์ด๋ฏธ์ง๋ฅผ dataURL๋ก ๋ณํํ ํ, ์ด๊ฒ์ indexedDB์ ์ ์ฅํ๋ค๊ฐ ๋ค์ ๋ถ๋ฌ์ฌ ๋ imageData๋ก ๋ค์ ๋ณํ์์ผ ์ฌ์ฉํ๋ฉด ๋์๋ค.
๊ทธ๋ฐ๋ฐ, ์ฌ๊ธฐ์ 2๋ฒ์ ๋ํ ๋ฌธ์ ์ ์ด ๋ฐ์ํ๊ฒ ๋์๋ค.
์ ์ ๊ฐ ๋ค์ ๋ค์ด์์ ๋, ๋ก์ปฌ์ ์ ์ฅ๋ ๋ฉ๋ชจ๋ค์ ๊ฐ์ง๊ณ dataURL => imageData๋ก ๋ณํ์ ์ํค๋ ๊ณผ์ ์์, ํ์ฐ์ ์ผ๋ก image ์ canvas๋ฅผ ์์ฑํด์ผ ํ๊ธฐ ๋๋ฌธ์ด์๋ค.
export function converURLToImageData(url: string | null) {
return new Promise<ImageData | null>((resolve, reject) => {
if (!url) return reject(null);
const canvas = document.createElement('canvas'); // 1. ์บ๋ฒ์ค๋ง๋ค๊ณ
const context = canvas.getContext('2d');
const image = new Image(); // 2. ์ด๋ฏธ์ง๋ง๋ค๊ณ
image.src = url;
image.addEventListener(
'load',
() => {
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0, canvas.width, canvas.height); // 3. ์ด๋ฏธ์ง ๊ทธ๋ฆฌ๊ณ
resolve(context.getImageData(0, 0, canvas.width, canvas.height)); // 4. imageData๋ฅผ ์ถ์ถํด์ผ ํ๋ค.
},
false,
);
image.addEventListener('error', () => reject(null));
});
}
์์๋ dataURL์ image ์ธ์คํด์ค ๋ฐ์ดํฐ๋ก ๋ณํ์ํค๋ ๋ก์ง์ ์ถ์ํํ ํจ์์ด๋ค.
์์ ๋ก์ง์ ๋ณด๋ฉด ์ด 4๊ฐ์ง์ ํ๋ก์ธ์ค๋ฅผ ๊ฑฐ์ณ์ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ป๊ณ ์ถ์ ๊ฐ์ ๊ฐ์ง๊ฒ ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋ถํํ ์คํธ๋ก ์ง์ 200๋ฒ์ ๊ทธ์ด๋ณธ ๋ค์ ์๋ก๊ณ ์นจ์ ํด์ 200๊ฐ์ dataURL์ imageData๋ก ๋ณํํ๋ ์ผ์ด์ค๋ฅผ ์๋ํด๋ณธ ๊ฒฐ๊ณผ, dataURL์ด๋ผ ํ ์ง๋ผ๋ ์๋นํ๊ฒ ๋ฒ๋ฒ ์ธ ํ ๋๋ก์ ๋ฐ์ดํฐ๊ฐ ์ ๋ฐ์ดํธ๋๋ ํ์์ ๋ชฉ๊ฒฉํ๊ฒ ๋์๋ค.
๊ทธ๋์ dataURL๋ก ๋ฐ๊พผ ๊ฒ ๋ฟ๋ง ์๋๋ผ ๊ทผ๋ณธ์ ์ผ๋ก indexedDB์ ์ ์ฅ๋์ด ์๋ ๊ฐ ์์ฒด๊ฐ ๋ง์์๋ ์๋๋ค๋ ๊ฒฐ๋ก ์ด ๋ฌ๋ค.
๊ทธ๋ด๋ ค๋ฉด ์ ๊ตํ๊ฒ ์บ๋ฒ์ค์์ ์ ์ฅ๋ ์ด๋ฏธ์ง๋ฅผ ์ ๋ณํ๊ฑฐ๋ ์์ ํตํฉ์ํค๋ ์ต์ ํ ๋ก์ง์ด ํ์ํ์๋ค.
ํ์ฌ undo, redo ๋ฅผ ๊ตฌํํ๊ธฐ ์ํด์ ๊ทธ๋ฆด ๋๋ง๋ค useRef์ current ๋ด ๋ฐฐ์ด์ drawPath ์ด๋ฏธ์ง๋ค์ ์ ์ฅ์ค์ด์๋ค.
์ด ์ด๋ฏธ์ง๋ค์ dataURL์ indexedDB์ ์ ์ฅํด์ผ ํ๋๋ฐ, ์ฌ์ง๊ป ๊ทธ๋ ค์๋ ๋ชจ๋ drawPath๋ค์ ์ ๋ถ ํ์ด๊ฐ๋ฉด์ ๋ญ ์ ์ฅํด์ผํ๋์ง ์ ๋ณํ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๊ณ ์คํ๋ ค ๋๋ก์์ ํ๋ฉด์ ํด๋น javascript๋ฅผ ์ฒ๋ฆฌํ๋ฉด์ ๋ฒ๋ฒ ์์ ๋ง๋ค ๊ฒ์ด ๋ปํ๋ค.
์ฌ๋ฌ๋ฒ ์๋๋ฅผ ํด๋ณธ ๊ฒฐ๊ณผ, ๋ง์ฝ ์ฌ์ฉ์๊ฐ ๋ฐ์ํ์ผ๋ก ํด๋ผ์ด์ธํธ ์ฌ์ด์ฆ๋ฅผ ์ค์ฌ์ ๋๋ก์ํ์ ๊ฒฝ์ฐ ๊ทธ ์ ๊น์ง ๊ทธ๋ฆฌ๊ณ ์๋ ๋ง์ง๋ง ์บ๋ฒ์ค๊ฐ ์ต๋ํฌ๊ธฐ์ ์ค๋ ์ท์ด ๋๋ค๋ ์ฌ์ค์ ํ์ ํ์๊ณ ,
๊ฐ์ฅ ํต์ฌ์ ์ผ๋ก ๊ฐ๊ณ ์์ด์ผ ํ๋ Image๋ง ๋ฉ๋ชจ๋ผ์ด์งํ์ฌ ๊ณ์ฐํด์ผ ํ๋ ๋ด์ฉ๋ค์ ์์ถํ๋ฉด ๋๋ค๋ ๊ฒฐ๋ก ์ ์ป์ ์ ์์๋ค.
const updateMemorizedImageData = async (newMemoImage: ImageData) => {
const { width: newImageWidth, height: newIamgeHeight } = newMemoImage;
const { width: memorizedPrevWidth, height: memorizedPrevHeight } = memoPrevImageSize.current;
const isPrevMemoBigger = newImageWidth < memorizedPrevWidth || newIamgeHeight < memorizedPrevHeight;
// ์ด์ ๊น์ง ๊ทธ๋ฆฌ๋ ์ฌ์ด์ฆ๋ณด๋ค ์์ ์ฌ์ด์ฆ์์ ๊ทธ๋ฆฌ๊ฒ ๋ ๊ฒฝ์ฐ
// drawPathRef์ ๊ธฐ๋ก๋๋ ๊ฐ์ฅ ๋ง์ง๋ง์ ๊ธฐ๋ก = ์ต๋์ฌ์ด์ฆ ์ค๋
์ท์ด๋ฏ๋ก ์ด๊ฒ๋ง ์ ์ฅํ์ฌ ์ต์ข
์ ์ฅ ๋ฐ์ดํฐ ์ฉ๋ ์ต์ ํ
// ํด๋น ์ต์ ํ๊ฐ ์์ ๊ฒฝ์ฐ, ๋ชจ๋ ๊ทธ๋ ค์ง drawPath์ ๋ํด์ redrawํ๊ฒ๋๋ฏ๋ก ์์ ํ๋ค.
if (isPrevMemoBigger) {
const biggerMemoImage = drawPathRef.current[drawPathRef.current.length - 1]; //๋ฐ์ํ ์ ์ต๋ํฌ๊ธฐ ์ค๋
์ท
memorizedImageData.current.push(biggerMemoImage);
// ์ถ๊ฐ ์ต์ ํ
// ๊ฐ๋ฅ์ฑ์ ์ ์ง๋ง, ๋๊ตฐ๊ฐ๊ฐ ์น์ฌ์ดํธ์์ ๋ฉ๋ชจ๊ธฐ๋ฅ์ ์ธ ๋ ํ๋ฉด ํฌ๊ธฐ๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ์ค์๋ค ๋์๋ค๋ฅผ ๋ฐ๋ณตํ๋ฉฐ ๊ทธ๋ฆด ๊ฒฝ์ฐ
// memorized๋๋ ์ผ์ด์ค๊ฐ ์ ์ ๋์ด๋๊ฒ ๋๋ค => ์ ์ฅํ ๋ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ ์ ์๋ค.
// ๋ฐ๋ผ์, ๊ณ์ ์ง์์ ์ผ๋ก memorized ๋๋ ์ด๋ฏธ์ง์ ๊ฐฏ์๊ฐ ๋์ด๋๊ธฐ ๋ณด๋ค, memorized ๋์ด์๋ ๋ฐฐ์ด์์ ์ต๋ ์ฌ์ด์ฆ์ ์บ๋ฒ์ค๋ฅผ ๋ง๋ค๊ณ , ๋ฉ๋ชจ๋ฅผ ๋ณํฉํ์ฌ ํ๋์ ๋ฉ๋ชจ๋ง ๊ด๋ฆฌํ๋ค.
// ํด๋น ์์
์ ๋ฐ์ํ์ด ๋ฐ์ํ๋ ์๊ฐ์ ํญ์ 3๊ฐ์ ์บ๋ฒ์ค์ ๋ํด์๋ง ๋ฐ์ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์, ๋น๊ต์ ๋ถ๋ด์ด ์ ๋ค.(ํ์ฌ์ด๋ฏธ์ง, ๊ธฐ์กด ์ด๋ฏธ์ง, ๋ฉ๋ชจ๋ผ์ด์ง๋์๋ ์ต๋์ฌ์ด์ฆ ์ด๋ฏธ์ง)
const { mergedImageData, dataURL } = genMergedImageData([
newMemoImage,
biggerMemoImage,
...memorizedImageData.current,
]);
memorizedImageData.current = [mergedImageData];
mergedDataURL.current = dataURL; // ์ต์ข
์ ์ผ๋ก indexedDB์ ์ ์ฅ๋ ์ต๋ํฌ๊ธฐ์ ์บ๋ฒ์ค ์ด๋ฏธ์ง dataURL
}
};
๋งฅ๋ฝ์์ด ๊ฒฐ๋ก ์ ์ธ ์ฝ์ด์ฝ๋๋ง ์ ํ์์ผ๋ ๋ญ๊ฐ ์ถ์ง๋ง, ๊ฒฐ๋ก ์ ์ผ๋ก ๋งํ๊ณ ์ถ์๋ ๋ด์ฉ์ ํ๋๋ค.
๋ฐ์ดํฐ๊ฐ ์ ์ฅ์ด ๋๊ฒ ๋๋ค๋ฉด, ์ด ๋ฐ์ดํฐ์ ๊ด๊ณ์ฑ์ ๋ณด๊ณ ํต์ผ์ ์ํฌ ์ ์๋ ์ฌ์ง๊ฐ ์กด์ฌํ๋ค๋ฉด ํํฐ๋งํ์ฌ ์ต์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ๊ฐ์ง ์ ์๋๋ก ํด์ผ ํ๋ค. ๋ฌด์ง์ฑ์ผ๋ก ๋ค ๋๋ ค๋ฃ์ง ๋ง๊ณ .
์ด ๋ชจ๋ ๊ณผ์ ์ด ์งํ๋์๋ ๊ทผ๋ณธ์ ์ธ ๋ฌผ์์ ์ด๊ฒ ์ ๋ง ์ต์ ์ด์ผ? ๋ผ๋ ๊ฒ์ด์๊ณ , ๋ถ์กฑํ์ง๋ง ๊ณ์ ๊ณ ๋ฏผํด๋๊ฐ๋ค ๋ณด๋ ๊ฐ์ ์ ํ ์ ์๋ ์ฌ์ง๋ค์ด ์กด์ฌํ๋ค.
๊ณ ์ง์ด๋ผ๋ฉด ๊ณ ์ง์ด๊ฒ ์ง๋ง ์ด ๊ณ ์ง์ ํตํด์ ๋ ๋์ ํผํฌ๋จผ์ค๋ฅผ ๋์ถํ ์ ์์๊ธฐ ๋๋ฌธ์ ์ ์งํ ์ ์์ผ๋ฉด ์ข์ ์์ธ๋ผ๊ณ ์ฌ๊ธฐ๊ณ ์๋ค.
๐ฃ ํ์ตํ ๋ด์ฉ
๋ก์ปฌ ์ฌ์ฉ์๊ฐ ๊ท์์ ์ผ๋ก ๊ฐ๊ฒ ํ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ๊ณ ๋ฏผํ๋ค๋ฉด, transaction์ ์ด์ฉํ์ฌ ์์ ํ๊ฒ CRUD์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ indexedDB๋ฅผ ์ฌ์ฉํ๋ ์๋จ์ ๋ฐฐ์ ๋ค.
์น์์ ๋ง์ฐ์ค๋ก ์ ๊ทธ๋ ค์ง๋ ๊ฒ์ ํ์ธํ๊ณ ๋ ๋ค ๋๋ฌด ๊ธฐ๋ถ์ด ์ข์๋ค.
๊ทธ๋ฐ๋ฐ ์๊ฐํด๋ณด๋ฉด, ๋ด๊ฐ ์๋ ๋ชฉํ๋ก ํ๋ ๊ฒ์ ์ด ์ด๋ ฅ์๋ฅผ "์์ดํจ๋์ ๊ฐ์" ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ๋ก ๋ณด๋ ์ฌ๋๋ค์ด ํ ๋ฑ์ผ๋ก ๋ฉ๋ชจ๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ๊ธฐ ๋๋ฌธ์, ํฌ๋กฌ์ ๊ฐ๋ฐ์๋๊ตฌ์์ ๋ชจ๋ฐ์ผ ๋ชจ๋๋ก ์ ํํ ๋ค ๊ทธ๋ ค๋ณด์๋ค. ๋น์ฐํ๊ฒ๋ ์๋ฌด๋ฐ ์ผ๋ ์ผ์ด๋์ง ์์๋ค.
์ด๋ฒคํธ ํ์
์ด ๋ค๋ฅธ๋ฐ(๋ง์ฐ์ค ํด๋ฆญ๊ณผ ํฐ์น ๋ฑ)
์ด ์ด๋ฒคํธ๋ฅผ ๋ค๋ฃจ๋ ํธ๋ค๋ฌ๊ฐ ๋ฌ๋ฆฌ ์ ์ฉ๋์ผ ํ๋ ๊ฒ๋ ๋น์ฐํ ์ด์น์ผ ๊ฒ์ด๋ค.
๊ทธ๋์ ํธ๋ค๋ฌ๋ฅผ ์์ฑํ๋ ค๋ค๊ฐ, ์ด์ฐจํผ ๋์ผํ ํ๋์ ํ ๊ฒ ๊ฐ์๋ฐ ๊ทธ๋ฅ ํ๋์ ํจ์์์ ๋ถ๊ธฐ์ฒ๋ฆฌํ๋ฉด ๋์ง ์์๊น?
ํ๊ณ ํ ํจ์ ๋ด์ ๋ชจ๋ ๊ฒ์ ๋ค ์์ฑํ๋ ค๊ณ ํ์๋ค.
์ผ์ ๊ธฐ์ด ์ง์์ ์ค์์ฑ์ ๋ํด์ ์ ์ด๋ ๋ธ๋ก๊น ์์๋ ๊ฒฝํํ๋ ์ผ์ด์ง๋ง, ์ ๋ฐฐ๋ค์ด ๊ตณ์ด ํจํด์ด๋ ์์น๋ค์ ๋ง๋ค์ด ๋๋ ๊ฒ์๋ ๋ค ์ด์ ๊ฐ ์๋ค๋ ๊ฒ์ ์ต๊ทผ๋ค์ด์ ๋ผ์ ๋ฆฌ๊ฒ ๋๋ผ๊ณ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ฒ์ (๋ฌผ๋ก ์์ฐํ ๋งํ์๋ฉด ์ข ๋ฒ์๋ ๋ค๋ฅด์ง๋ง) SRP์ ๊ด๋ จํ ๋น์ทํ ๊ฒฝํ์ด๋ผ๊ณ ๋๋ฆ ์๊ฐ์ ์ ๋ฆฌํด๋ณธ๋ค.
SRP๋ ํ ํด๋์ค๊ฐ ๊ฐ์ ธ์ผ ํ๋ ๊ด์ฌ์ฌ ํน์ ์ฑ ์์ ๋ช ํํ๊ฒ ๊ตฌ๋ถ๋์ด์ผ ํ๋ค๋ ๊ฒ์ด๋ค. ํ๋์ ํด๋์ค๊ฐ ๋ค์ํ ์ผ์ ํด์๋ ์๋๋ค๋ ์์น์ด๋ค.
ํด๋์ค๊ฐ ์์ ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๋ฉ์๋๋ค์ ๊ณ์ํด์ ๊ฐ๊ฒ ๋์ด ์ฑ ์ ์์ง๊ฐ ๋์ด๋๋ ์๊ฐ, ์ฝ๋ ์์ ์ด ์ผ์ด๋๊ฑฐ๋ ์๋ฌ๊ฐ ๋ฐ์ ์ ์ฐ์์ ์ธ ๋ฌธ์ ๊ฐ ์ผ์ด๋ ๊ฐ๋ฅ์ฑ์ด ๋์์ง๋ค.
ํญ์ ํต์ฌ์ ์ผ๋ก ๊ธฐ์ตํ ๊ฒ์, ํด๋น ํด๋์ค๊ฐ ์ด๋ ํ "์ผ" ์ ํด์ผํ๋ ์ง, ๊ทธ๋ฆฌ๊ณ ํด๋น ํด๋์ค๊ฐ ๋ณ๊ฒฝ๋์ด์ผ ํ๋ ์ฌ์ ๋ ์ค๋ก์ง ๊ทธ "์ผ" ๊ณผ ๊ด๋ จ๋ ์ฌ์ ์ ๋ณ๊ฒฝ์ ํํด์์ด๋ค.
์ฑ ์์ด ํ๋๋ผ๋ฉด, ๋ณ๊ฒฝ ์ด์ ๋ ํ๋์ฌ์ผ ํ๋ค. ๋ ์์ธํ ๋ด์ฉ์ ๋ค๋ฅธ ๋ถ์ ๋ธ๋ก๊น ์ ์ฐธ์กฐํ๋ฉด ์ข๋ค.
์ต๊ทผ์ ๋ค์ ๊ธฐ์ด OOP๋ฅผ ๊ณต๋ถํ๋ค๊ฐ ๋ด๊ฐ ์์ฑํ๋ ์ฝ๋๋ฅผ ๋ณด๋ฉด์ ๋๋ผ๋ ๊ฒ์ธ๋ฐ ํจ์ ์ญ์๋ ํ๋์ ์ฑ ์์์น์ ๋ฐ๋ผ ๋ถ๋ฆฌ๋์ด ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ข๋ค๋ ์๊ฐ์ด ๋ ๋ค.
์์ ์ฌ์ง์ ์น์์ ๋๋ก์์ ์์ํ ๋ ํธ์ถ๋๋ ํจ์ startDrawing ์, ๋ชจ๋ฐ์ผ์์ ์ฌ์ฉ๋๋ ํจ์ startDrawingForMobile์ ๋ชจ์ต์ด๋ค.
์์ ์๋ ๋ก์ง์ด ๋์ผํ๋ค๋ ๊ฒ์ ์ ์ ์๋ค (checkPointerType์ ํธ์ถํ๋์ง์ ์ ๋ฌด๋ง ๋นผ๋ฉด).
์ค์ ๋ก, ์ฒ์์ ๊ตฌํํ ๋์๋ ์ ์ด๋ถํฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ๋๋ก ๋๋ ๋์ง๋ ์์์๋ค.
๊ทธ๋ฅ ํ๋์ "StartDrawing"์ด๋ผ๋ ๊ฐ๋ ์๋์ ๋ฉ์๋๋ฅผ ๊ณต์ฉ ์ปดํฌ๋ํธ๋ง๋ฅ ๋ฌถ๊ณ ๋ด๋ถ์์ ์ผ์ด์ค๊ฐ ๋ถ๋ฆฌ๋ ์ํฉ์ด ์กด์ฌํ๋ค๋ฉด "if....๋ชจ๋ฐ์ผ์ด๋ฉด" ์ด๋ฐ์์ผ๋ก ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํ์๋ค.
๊ทธ๋ฐ๋ฐ, ๊ทธ๋ฌ๋ค๋ณด๋๊น ์ ์ ํ๋์ ๋ฉ์๋๊ฐ ํด์ผ ํ๋ ์ผ์ด ๋ง์์ ธ๊ฐ๊ณ , ์ฝ๋๊ฐ ์ฅํฉํด์ง๋ ๊ฒ์ ๋ชฉ๊ฒฉํ๊ฒ ๋์๋ค.
์๋๋ ์์ ์ดํ ์ค์ ๋๋ก์์ ์ผ์ผํค๋ onDrawing๊ณผ ๊ด๋ จํ์ฌ ๋ ํธ๋ค๋ฌ์ ๋ก์ง์ ๋ณด์ฌ์ค๋ค.
const onDrawing = (e: React.MouseEvent<HTMLCanvasElement, MouseEvent>) => {
const context = canvasCtxRef.current;
const x = e.pageX;
const y = e.pageY;
if (isCanvasOpen) {
if (!isDrawing) { // ๋๋ก์์ด ์๋ ๋, ์ฆ ๊ทธ๋ฅ ์บ๋ฒ์ค ์์ ๋ง์ฐ์ค๊ฐ ์์ง์ด๊ณ ๋ง ์์ ๋์ ์ผ์ด์ค ๋ถ๋ฆฌ
context?.beginPath();
context?.moveTo(x, y);
} else {
applymemoContextAttr();
context?.lineTo(x, y);
context?.stroke();
}
}
};
const onDrawingForMobile = (e: React.PointerEvent<HTMLCanvasElement>) => {
checkPointerType(e.pointerType, () => {
const context = canvasCtxRef.current;
const x = e.pageX;
const y = e.pageY;
if (isCanvasOpen) { // ๋ชจ๋ฐ์ผ์๋ ๋ง์ฐ์ค ํฌ์ธํฐ ๊ฐ๋
์ด ์์ผ๋ฏ๋ก, ๋ถ๋ฆฌ๋ ํ์๊ฐ ์๋ค.
applymemoContextAttr();
context?.lineTo(x, y);
context?.stroke();
}
});
};
๋ถ๋ช ํ ์ด๋ฐ ๋ณ์์ ์ธ๊น์ง ๊ฐ์๋ฐ, ๋ถ๊ธฐ์ ๋ถํฐ๊ฐ ๋ฌ๋ผ์ง๋ค.
์ด๊ฒ์ ๋ง์ฐ์ค์ ๋ชจ๋ฐ์ผ ๋๋ฐ์ด์ค๊ฐ์ ์ฐจ์ด๋๋ฌธ์ ๋ฐ์ํ๋ ๊ฒ์ธ๋ฐ, ๋ง์ฐ์ค์ ๊ฒฝ์ฐ beiginPath์ moveTo๋ฅผ ํธ์ถํ์ฌ์ ์ด๊ธฐ์ง์ ์ ๊ณ์ ์ด๊ธฐํํด์ฃผ์ง ์์ผ๋ฉด ๊ทธ๋ฆฌ์ง ์์ ์ฑ๋ก ๋ง์ฐ์ค๋ฅผ ์ด๋ํ๋ค๊ฐ ํด๋ฆญ ์, ๋ง์ง๋ง ์ฅ์์์ ํ์ฌ ์ฐ์ ์ฅ์๊น์ง ์ง์ ์ด ๊ทธ๋ ค์ ธ๋ฒ๋ฆฐ๋ค.
๊ทธ๋ฐ๋ฐ ๋ง์ฝ ๊ณต์ฉ ์ปดํฌ๋ํธ๋ง๋ฅ ๋ ๋ค๋ฅธ ํ์ ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ง ํธ๋ค๋ฌ๋ฅผ ํฉ์ณ์ ํ๋๋ก ๋ฌถ๊ฒ ๋๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
์ฝ๋์์ผ๋ก๋ ๊ทธ๊ฒ ๋ ํ์ค์ด๋ผ๋ ์ค์ด๋ ์ผ์ผ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ, ๋ด๋ถ์ ์ผ๋ก ์ ๋ง ์ง์ ๋ถํ ๊ฒ์ด๋ค.
์ ๋ถ๊ธฐ์ ์ ๋ํ ๋ด์ฉ์ด ์ถ๊ฐ๋์ด์ผ ํจ๊ณผ ๋์์, ์์ง๊น์ง ์ธ๊ธํ์ง ์์๋ ์กด์ฌ "checkPointerType" ๊น์ง ์ถ๊ฐ๋๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น.
const checkPointerType = (pointerType: 'mouse' | 'touch' | 'pen', callback: Function) => {
if (pointerType === drawType) {
callback();
}
};
์ ํจ์๋ ํ์ฌ ์ ์ญ recoil์์ ๊ด๋ฆฌ๋๋ ์ํ์ ์ธ์๋ก ๋ค์ด์ค๋ ์ด๋ฒคํธ ํ์ ์ ๋น๊ตํ์ฌ ์ฝ๋ฐฑํจ์๋ฅผ ์คํ์ํฌ์ง์ ์ ๋ฌด๋ฅผ ๊ฒฐ์ ํ๋ ๋ฏธ๋ค์จ์ด๋ค.
์ด ๋ฏธ๋ค์จ์ด๋ฅผ ๊ตฌํํ ์ด์ ๋ ํ ๋ฆฌ์ ์ (์๋ฐ๋ฅ์ด ์ ์ด ์ ํฐ์น๋ก ์ธ์๋์ด ๊ทธ๋ ค์ง๋ ๋ฌธ์ ์ผ์ด์ค) ๋๋ฌธ์ธ๋ฐ ์ด๊ฒ์ ์ผ๋จ ์ฌ์กฑ์ด๋ ๋์ด๊ฐ๊ณ ,
๋ค์๊ธ ๋งํ์ง๋ง ์ด ๋ชจ๋ ๊ฒ๋ค์ ๋ค ๊ณ ๋ คํด์ ํ๋์ ํจ์์ ํตํฉํ๋ค๊ณ ๊ฐ์ ํ์.
const onEveryDrawing = (
e: React.MouseEvent<HTMLCanvasElement, MouseEvent> | React.PointerEvent<HTMLCanvasElement>,
) => {
const context = canvasCtxRef.current;
const x = e.pageX;
const y = e.pageY;
if ((e as React.PointerEvent<HTMLCanvasElement>).pointerType) {
const pointerType = (e as React.PointerEvent<HTMLCanvasElement>).pointerType;
if (pointerType === drawType && isCanvasOpen) {
applymemoContextAttr();
context?.lineTo(x, y);
context?.stroke();
}
} else if (isCanvasOpen) {
if (!isDrawing) {
context?.beginPath();
context?.moveTo(x, y);
} else {
// ๊ทธ๋ฆด ๋, ํด๋น ์ขํ๊น์ง ํฝ์
๊ฒฝ๋ก๋ฅผ ๋ง๋ค๊ณ (lineTo) ๊ทธ ํฝ์
์ ์ฑ์๋ฃ์ด์ ๋ผ์ธ์ ๋ง๋ ๋ค(stroke).
applymemoContextAttr();
context?.lineTo(x, y);
context?.stroke();
}
}
};
์ ๊ฒ ๊ณผ์ฐ ๋ญ ์ด๋๊น์ง ํ๋ ํจ์์ธ์ง ๊ตฌ๋ณ์ด ๊ฐ๋๊ฐ
ํ์
์คํฌ๋ฆฝํธ๋ก ์์ฑํ๊ฒ ๋๋ค๋ฉด ํ์
๊ฐ๋๋ฅผ ์ํ ์ฝ๋๋ ์ถ๊ฐ๋์ด์ผ ํ๊ณ ,
๋ง์ฝ ์ด๋ฒคํธ๋ก ์ค๋ ๊ฐ์ ํ์ํ ๊ฐ์ด ์กด์ฌํ์ง ์๋๋ค๋ฉด ํด๋น ๊ฐ์ ํตํด ํ์ํ ๊ฐ์ ๋ณํํ๋ ๋ณํํจ์๋ ์ถ๊ฐ๋์ด์ผ ํ๋ค.
(์๋ฅผ ๋ค์ด, ์ด๋ฒคํธ๋ฅผ ํฐ์น์ด๋ฒคํธ๋ก ๊ตฌํํ๋ คํ๋ค๋ฉด ํด๋น ์ด๋ฒคํธ ๊ฐ์ฒด ๋ด์๋ pageX๊ฐ ์๋ค. touches ํ๋กํผํฐ์ ์๋ ๊ฐ์ ๊ณ์ฐํด์ offsetX๋ก ๋ณํํ์ด์ผ ํ๋ค)
๊ฒ๋ค๊ฐ ์ ๊ฑฐ๋ ์์ฃผ ๊ฐ๋จํ ๋ก์ง์ด๋๊น ์ง๊ธ์ ์ฝ์ ์ ์๋ค๊ณ ์น์ง๋ง,
์ค์ ์๋น์ค์์ ์ฌ๋ฌ๊ฐ์ง ํจ์๋ฅผ ํ๋๋ก ๋ฌถ์ ์ ์์ ๊ฒ ๊ฐ๋ค๊ณ ํจ๋ถ๋ก ๋ฌถ๋๋ค๊ณ ๊ฐ์ ํ์.
// ์์๋๋ ์กฐ๊ฑด๋ฌธ ์ง์ฅ๋
export function service(){
if(){
if(){
if(){
if(){
if(){}
}
}
}
}else if(){
if(){
if(){
}
}else if(){
}else if(){
if(){
}
}
}
}
์ฝ๋๊ฐ ๋ถ๋ฆฌ๋์ด ์ฌ๋ฌ๊ฐ๊ฐ ์๊ธฐ๊ธด ํ์ง๋ง, ํน์ ์ด๋ฒคํธ์ ๋ํด์ ํน์ ์ฑ
์์ ์ง๋ ํธ๋ค๋ฌ๋ฅผ ๋ฐ๋ก ๋ถ๋ฆฌํด์ ์ ์ธ์ ์ผ๋ก ์์ฑํ๋ ํธ์ด ์ถํ ์ ์ง๋ณด์
๋ฐ ์ฝ๋ ๊ฐ๋
์ฑ
์ ์์ด์ ํจ์ฌ ๋์์ด ๋๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค.
์ฆ, ์ด ํจ์๊ฐ ์ด๋ ํ "์ฑ ์"์ ๊ฐ๊ณ ๋์ํ๋ ์ง์ ๋ํด์ ๋ช ํํ๊ฒ ๊ตฌ๋ถ์ ์ง์ ์ ์๋ค๋ ๊ฒ์ด๋ค.
๋ฌผ๋ก ๋ฐ๋ณต๋๋ ๋ก์ง์ ๋ํด์ ์๋ฏธ์์ด ๊ณ์ ๋์ผํ๊ฒ ๋ฐ๋ณต ์์ฑํ๋ ๊ฒ ์ญ์ ์ณ์ง๋ ๋ชปํ๋ค.
๊ทธ๋ฌ๋ฏ๋ก, ํด๋น ๋ฐ๋ณต๋์ด ๋ณด์ด๋ ๋ด์ฉ์ด ๊ณต์ฉ์ ์ผ๋ก ์ฌ์ฉํ๊ณ ์ถ์ ๋ ์ด๊ฒ์ด "์ฑ ์๋ก "์ ์ผ๋ก ํ๋์ ๋์์ผ๋ก ๋ฌถ์ด์ง ์ ์๋ค๊ณ ํ๋ค๋ฉด ์ฑ ์๋จ์๋ก ๋ฌถ์ด์ ํธ์ถ์ํค๋ ๊ฒ๋ ์ข๋ค๊ณ ๋ณธ๋ค.
๐ฃ ํ์ตํ ๋ด์ฉ
๋๋ฌด ํด๋ฆฐ ์ฝ๋๋ง ๊ณ ์งํ์ฌ ํจ์๋ฅผ ๋ฌด๋ฆฌํ๊ฒ ์ผ๋ฐํ์ํค๋ ค๊ณ ํ์ง ๋ง๊ณ ์ ํํ ์ฑ
์ ์๋ฆฌ์ ๋ฐ๋ผ ๊ตฌ๋ถํ์ฌ ๋ก์ง์ ์์ฑํ๋ ์ต๊ด์ ๋ค์ด์.
์ด ์ธ์๋, Ref๋ก ๋น์ ์ดํ ๊ฐ์ ์ฌ์ฉํ์ ์ ์ฅ์ ๊ณผ ์ ์์ , ๋ฉ์๋๋ค์ Class๋ก ๋ถ๋ฅํ์์ ๋์ ํ์ฅ์ฑ์ ๋ํ ํธ๋ฆฌํจ ๋ฑ๋ ๋์ดํ๊ณ ์ถ์ ์ฃผ์ ์ด๊ธด ํ์ง๋ง ๋ญ๊ฐ ์์์ ์ ์๋ ๋ด์ฉ์ด ์๋ฌ์ ๊ด๋ จ๋ ๋ด์ฉ์ ๊ฐ๊น๊ธฐ์ ๊ฒฐ์ด ๋ค๋ฅธ ๊ฒ ๊ฐ์์ ์์ ๋ด์ฉ์ ๋ค๋ฅธ ์ฃผ์ ๋ก ๋๊ณ ์ฐ๋ ค๊ณ ํ๋ค.
ํญ์ ๊ฐ๋ฐ์ ํ๋ค๋ณด๋ฉด ๋์์ ์๋ ๊ฒ๋ง ๋ณด๊ณ ์ ๋ถ ๋ค ๊ตฌํํ๋ค๊ณ ์ฐฉ๊ฐํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ค.
๊ทธ๋ฐ๋ฐ ์ด๋ฒ์ ํ ์ด ํ๋ก์ ํธ๋ฅผ ๊ฒฝํํ๋ฉด์, ๊ฐ๋จํด ๋ณด์ด๋ ๊ธฐ๋ฅ์ด๋ผ๋ ์ค์ ๋ก๋ ์ธ์ธํ๊ฒ ๊ณ ๋ฏผํ๊ณ ๊ณ ๋ คํด์ผ๋ ๋ถ๋ถ์ด ๋ง๋ค๋ ์ฌ์ค์ ๊นจ๋ฌ์๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ฒฝํ๊ฒ ์๋ฌ์๋ ๊ฐ๋ฐ์ ์กด์ฌํ ์ ์์ง๋ง, ์ด๋ฐ ๊ณ ๋ฏผ์ ๋ค์ด ๋ฐ๊ฒฌ๋์์ ๋ ํ๋ํ๋ ์์ ํด๊ฐ๊ณ ๋ณด์ํด๊ฐ๋ ๊ฒ์ด ๊ฐ๋ฐ์ ์์ฑ๋๋ฅผ ๋์ฌ๊ฐ๋ ๊ธธ์ด๋ฉฐ ์ํ์ฐฉ์ค๋ฅผ ์กฐ๊ธ์ด๋ผ๋ ๋ ์ค์ด๊ธฐ ์ํด์ ํญ์ ํ์์ ๊ธฐ์ด์ ์๋ฆฌ๋ฅผ ์ ์์งํ๊ณ ๊ณ ๋ฏผํด์ผ ํ๋ค๋ ์ฌ์ค์ ๊นจ๋ซ๋ ํ๋ฃจ์๋ค.