# Drawing Module API ๋ฌธ์ ## ๐ ๊ฐ์ Drawing Module์ ์น ๋ธ๋ผ์ฐ์ ์์ ์ฌ์ฉํ ์ ์๋ ๋ ๋ฆฝ์ ์ธ Canvas ๊ธฐ๋ฐ ๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ์ ๋๋ค. ๋ชจ๋ฌ ํํ์ UI๋ฅผ ์ ๊ณตํ๋ฉฐ, ๋ค์ํ ๊ทธ๋ฆฌ๊ธฐ ๊ธฐ๋ฅ๊ณผ ์ด๋ฏธ์ง ํธ์ง ๊ธฐ๋ฅ์ ํฌํจํฉ๋๋ค. ## ๐ ๋น ๋ฅธ ์์ ### 1. ํ์ผ ํฌํจ ```html
``` ### 2. ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ ```javascript // ๊ธฐ๋ณธ ์ธ์คํด์ค ์์ฑ const drawer = new DrawingModule({ container: 'body', onSave: (data) => { console.log('์ ์ฅ๋ ์ด๋ฏธ์ง:', data.imageData); console.log('์ ์ฅ ์๊ฐ:', data.timestamp); } }); // ๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ ํ์ drawer.show(); ``` ## ๐ API ์ฐธ์กฐ ### ์์ฑ์ (Constructor) ```javascript new DrawingModule(options) ``` #### ์ต์ ๋งค๊ฐ๋ณ์ | ์ต์ | ํ์ | ๊ธฐ๋ณธ๊ฐ | ์ค๋ช | |------|------|--------|------| | `container` | string | 'body' | ๋ชจ๋ฌ์ ์์ฑํ ์ปจํ ์ด๋ ์ ํ์ | | `width` | number | 800 | ๋ชจ๋ฌ์ ์ ์ฒด ๋๋น (px) | | `height` | number | 600 | ๋ชจ๋ฌ์ ์ ์ฒด ๋์ด (px) | | `canvasWidth` | number | 320 | ์บ๋ฒ์ค์ ์ค์ ๋๋น (px) | | `canvasHeight` | number | 240 | ์บ๋ฒ์ค์ ์ค์ ๋์ด (px) | | `title` | string | '๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ' | ๋ชจ๋ฌ ํค๋ ์ ๋ชฉ | | `initialImage` | string | null | ์ด๊ธฐ์ ๋ก๋ํ ์ด๋ฏธ์ง URL ๋๋ ๋ฐ์ดํฐ URL | | `onSave` | function | null | ์ ์ฅ ์ ํธ์ถ๋๋ ์ฝ๋ฐฑ ํจ์ | | `onCancel` | function | null | ์ทจ์ ์ ํธ์ถ๋๋ ์ฝ๋ฐฑ ํจ์ | #### ์ฝ๋ฐฑ ํจ์ ์๊ทธ๋์ฒ **onSave ์ฝ๋ฐฑ:** ```javascript onSave: (data) => { // data.imageData - base64 ์ธ์ฝ๋ฉ๋ ์ด๋ฏธ์ง ๋ฐ์ดํฐ // data.timestamp - ์ ์ฅ ์๊ฐ (Date ๊ฐ์ฒด) // data.width - ์บ๋ฒ์ค ๋๋น // data.height - ์บ๋ฒ์ค ๋์ด } ``` **onCancel ์ฝ๋ฐฑ:** ```javascript onCancel: () => { // ์ฌ์ฉ์๊ฐ ์ทจ์ ๋ฒํผ์ ํด๋ฆญํ์ ๋ ํธ์ถ } ``` ### ๋ฉ์๋ (Methods) #### show() ๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ ๋ชจ๋ฌ์ ํ์ํฉ๋๋ค. ```javascript drawer.show(); ``` #### hide() ๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ ๋ชจ๋ฌ์ ์จ๊น๋๋ค. ```javascript drawer.hide(); ``` #### loadImage(imageUrl) ์บ๋ฒ์ค์ ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํฉ๋๋ค. ```javascript drawer.loadImage('path/to/image.png'); // ๋๋ ๋ฐ์ดํฐ URL drawer.loadImage('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='); ``` #### clear() ์บ๋ฒ์ค์ ๋ชจ๋ ๋ด์ฉ์ ์ง์๋๋ค. ```javascript drawer.clear(); ``` #### getImageData() ํ์ฌ ์บ๋ฒ์ค์ ์ด๋ฏธ์ง ๋ฐ์ดํฐ๋ฅผ ๋ฐํํฉ๋๋ค. ```javascript const imageData = drawer.getImageData(); console.log(imageData); // base64 ๋ฌธ์์ด ``` ## ๐จ ์ฃผ์ ๊ธฐ๋ฅ ### ๊ทธ๋ฆฌ๊ธฐ ๋ชจ๋ - **์ ์ฐ๊ฒฐ (Polyline)**: ํด๋ฆญํ ์ ๋ค์ ์ฐ๊ฒฐํ์ฌ ์ ์ ๊ทธ๋ฆฝ๋๋ค - **์ง์ (Line)**: ์์์ ๊ณผ ๋์ ์ ํด๋ฆญํ์ฌ ์ง์ ์ ๊ทธ๋ฆฝ๋๋ค - **์์ ์ (Free)**: ๋ง์ฐ์ค๋ฅผ ๋๋๊ทธํ์ฌ ์์ ๋กญ๊ฒ ์ ์ ๊ทธ๋ฆฝ๋๋ค ### ์ถ๊ฐ ๊ธฐ๋ฅ - **์ง๊ฐ ๋ชจ๋**: ์ํ/์์ง์ ๋ง ๊ทธ๋ฆฌ๊ธฐ (์ฒดํฌ๋ฐ์ค๋ก ํ์ฑํ) - **์์ ์ ํ**: 16์ง์ ์ปฌ๋ฌ ํผ์ปค๋ก ์ ์์ ๋ณ๊ฒฝ - **์ ๊ตต๊ธฐ ์กฐ์ **: 1-10px ๋ฒ์์ ์ฌ๋ผ์ด๋๋ก ์ ๊ตต๊ธฐ ์กฐ์ - **์ง์ฐ๊ฐ**: ์ํ ์ง์ฐ๊ฐ๋ก ํน์ ์์ญ ์ญ์ (ํฌ๊ธฐ ์กฐ์ ๊ฐ๋ฅ) - **ํ ์คํธ ์ถ๊ฐ**: ํด๋ฆญํ ์์น์ ํ ์คํธ ์ ๋ ฅ - **์คํ์ทจ์ (Undo)**: ๋ง์ง๋ง ์์ ๋๋๋ฆฌ๊ธฐ - **์ด๊ธฐํ**: ์บ๋ฒ์ค์ ๋ชจ๋ ๋ด์ฉ ์ญ์ - **ํฐ์น ์ง์**: ๋ชจ๋ฐ์ผ/ํ๋ธ๋ฆฟ ๋๋ฐ์ด์ค ํฐ์น ์ด๋ฒคํธ ์ง์ ## ๐ฑ ์ฌ์ฉ ์์ ### 1. ๊ธฐ๋ณธ ๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ ```javascript const basicDrawer = new DrawingModule({ container: 'body', onSave: (data) => { // ์ด๋ฏธ์ง๋ฅผ ๋ก์ปฌ ์ ์ฅ์์ ์ ์ฅ localStorage.setItem('drawing', data.imageData); alert('๊ทธ๋ฆฌ๊ธฐ๊ฐ ์ ์ฅ๋์์ต๋๋ค!'); } }); basicDrawer.show(); ``` ### 2. ์ปค์คํ ํฌ๊ธฐ ์บ๋ฒ์ค ```javascript const largeDrawer = new DrawingModule({ container: '#myContainer', canvasWidth: 640, canvasHeight: 480, title: 'ํฐ ์บ๋ฒ์ค ๊ทธ๋ฆฌ๊ธฐ', onSave: (data) => { console.log(`์บ๋ฒ์ค ํฌ๊ธฐ: ${data.width}x${data.height}`); downloadImage(data.imageData, 'large-drawing.png'); } }); largeDrawer.show(); ``` ### 3. ์ด๋ฏธ์ง ํธ์ง ```javascript const imageEditor = new DrawingModule({ container: 'body', initialImage: '/path/to/existing-image.jpg', title: '์ด๋ฏธ์ง ํธ์ง', onSave: (data) => { // ํธ์ง๋ ์ด๋ฏธ์ง๋ฅผ ์๋ฒ์ ์ ๋ก๋ uploadImageToServer(data.imageData); }, onCancel: () => { console.log('์ด๋ฏธ์ง ํธ์ง์ด ์ทจ์๋์์ต๋๋ค.'); } }); imageEditor.show(); ``` ### 4. ์๋ฒ๋ก ์ด๋ฏธ์ง ์ ์ฅ ```javascript const drawer = new DrawingModule({ container: 'body', onSave: (data) => { // AJAX๋ก ์๋ฒ์ ์ด๋ฏธ์ง ์ ์ก $.ajax({ url: '/api/save-drawing', method: 'POST', data: { image: data.imageData, timestamp: data.timestamp.toISOString(), width: data.width, height: data.height }, success: function(response) { alert('์๋ฒ์ ์ ์ฅ๋์์ต๋๋ค!'); console.log('์ ์ฅ๋ ์ด๋ฏธ์ง ID:', response.imageId); }, error: function(error) { alert('์ ์ฅ์ ์คํจํ์ต๋๋ค: ' + error.responseText); } }); } }); drawer.show(); ``` ### 5. ๋ค์ค ์ธ์คํด์ค ```javascript // ๋์์ ์ฌ๋ฌ ๊ฐ์ ๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ ์ฌ์ฉ const drawer1 = new DrawingModule({ container: 'body', title: '๊ทธ๋ฆฌ๊ธฐ 1', canvasWidth: 200, canvasHeight: 200, onSave: (data) => console.log('Drawing 1 saved') }); const drawer2 = new DrawingModule({ container: 'body', title: '๊ทธ๋ฆฌ๊ธฐ 2', canvasWidth: 300, canvasHeight: 200, onSave: (data) => console.log('Drawing 2 saved') }); drawer1.show(); setTimeout(() => drawer2.show(), 100); // ์ฝ๊ฐ์ ์ง์ฐ ``` ## ๐ ๏ธ ์ ํธ๋ฆฌํฐ ํจ์ ### ์ด๋ฏธ์ง ๋ค์ด๋ก๋ ํจ์ ```javascript function downloadImage(dataUrl, filename) { const link = document.createElement('a'); link.download = filename; link.href = dataUrl; link.click(); } // ์ฌ์ฉ๋ฒ const drawer = new DrawingModule({ onSave: (data) => { downloadImage(data.imageData, 'my-drawing.png'); } }); ``` ### Base64๋ฅผ Blob์ผ๋ก ๋ณํ ```javascript function dataURLtoBlob(dataURL) { const arr = dataURL.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type: mime}); } // ์ฌ์ฉ๋ฒ const drawer = new DrawingModule({ onSave: (data) => { const blob = dataURLtoBlob(data.imageData); const formData = new FormData(); formData.append('image', blob, 'drawing.png'); // FormData๋ฅผ ์๋ฒ์ ์ ์ก fetch('/upload', { method: 'POST', body: formData }); } }); ``` ## ๐ฏ ํ์ผ ๊ตฌ์กฐ ``` project/ โโโ test_drawing.php # ํ ์คํธ ํ์ด์ง (PHP) โโโ css/ โ โโโ drawingModule.css # ์คํ์ผ์ํธ โโโ js/ โ โโโ drawingModule.js # ๋ฉ์ธ JavaScript ๋ชจ๋ โโโ drawModule.md # ์ด ๋ฌธ์ ``` ## ๐ง ์ปค์คํฐ๋ง์ด์ง ### CSS ์ปค์คํฐ๋ง์ด์ง ์ฃผ์ CSS ํด๋์ค๋ค์ ์ค๋ฒ๋ผ์ด๋ํ์ฌ ์คํ์ผ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค: ```css /* ๋ชจ๋ฌ ๋ฐฐ๊ฒฝ์ ๋ณ๊ฒฝ */ .dm-modal { background-color: rgba(0, 0, 0, 0.8); } /* ๋ฒํผ ์์ ๋ณ๊ฒฝ */ .dm-btn-primary { background-color: #custom-color; } /* ์บ๋ฒ์ค ํ ๋๋ฆฌ ์คํ์ผ ๋ณ๊ฒฝ */ #dmCanvas { border: 3px solid #custom-border-color; } ``` ### JavaScript ์ด๋ฒคํธ ํ ๋ชจ๋์ ๋์์ ์ปค์คํฐ๋ง์ด์งํ๋ ค๋ฉด ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ธ์: ```javascript const drawer = new DrawingModule({ onSave: (data) => { // ์ ์ฅ ์ ๊ฒ์ฆ if (data.width < 100 || data.height < 100) { alert('๊ทธ๋ฆผ์ด ๋๋ฌด ์์ต๋๋ค!'); return; } // ์ปค์คํ ์ ์ฅ ๋ก์ง customSaveFunction(data); }, onCancel: () => { // ์ทจ์ ์ ์ ๋ฆฌ ์์ cleanupResources(); } }); ``` ## ๐จ ์ฃผ์์ฌํญ 1. **jQuery ์์กด์ฑ**: ์ด ๋ชจ๋์ jQuery์ ์์กดํ๋ฏ๋ก jQuery๋ฅผ ๋จผ์ ๋ก๋ํด์ผ ํฉ๋๋ค. 2. **CSS ํ์ผ ํ์**: `drawingModule.css` ํ์ผ์ด ์์ผ๋ฉด UI๊ฐ ์ ๋๋ก ํ์๋์ง ์์ต๋๋ค. 3. **๋ธ๋ผ์ฐ์ ํธํ์ฑ**: HTML5 Canvas๋ฅผ ์ง์ํ๋ ๋ธ๋ผ์ฐ์ ์์๋ง ์๋ํฉ๋๋ค. 4. **์ด๋ฏธ์ง ํฌ๊ธฐ ์ ํ**: ๋งค์ฐ ํฐ ์บ๋ฒ์ค๋ ๋ธ๋ผ์ฐ์ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค. 5. **๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ**: ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ ๋๋ ์ฌ์ฉํ์ง ์๋ ์ธ์คํด์ค๋ฅผ ์ ์ ํ ์ ๋ฆฌํ์ธ์. ## ๐ ๋ฌธ์ ํด๊ฒฐ ### ์ผ๋ฐ์ ์ธ ๋ฌธ์ ๋ค **Q: ๋ชจ๋ฌ์ด ํ์๋์ง ์์์.** A: CSS ํ์ผ์ด ์ ๋๋ก ๋ก๋๋์๋์ง, ๊ทธ๋ฆฌ๊ณ `show()` ๋ฉ์๋๋ฅผ ํธ์ถํ๋์ง ํ์ธํ์ธ์. **Q: ๊ทธ๋ฆฌ๊ธฐ๊ฐ ์๋ํ์ง ์์์.** A: jQuery๊ฐ ๋ก๋๋์๋์ง, ๊ทธ๋ฆฌ๊ณ JavaScript ์ฝ์์ ์ค๋ฅ๊ฐ ์๋์ง ํ์ธํ์ธ์. **Q: ์ด๋ฏธ์ง ์ ์ฅ์ด ์ ๋ผ์.** A: `onSave` ์ฝ๋ฐฑ์ด ์ ๋๋ก ์ค์ ๋์๋์ง ํ์ธํ์ธ์. **Q: ๋ชจ๋ฐ์ผ์์ ํฐ์น๊ฐ ์๋ํ์ง ์์์.** A: ์ต์ ๋ฒ์ ์ ๋ชจ๋์ ์ฌ์ฉํ๊ณ ์๋์ง ํ์ธํ์ธ์. ํฐ์น ์ด๋ฒคํธ๋ ์๋์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. ## ๐ ๋ผ์ด์ ์ค ์ด ๋ชจ๋์ MIT ๋ผ์ด์ ์ค ํ์ ๋ฐฐํฌ๋ฉ๋๋ค. ## ๐ ์ ๋ฐ์ดํธ ๋ด์ญ - **v1.0.0**: ์ด๊ธฐ ๋ฆด๋ฆฌ์ค - ๊ธฐ๋ณธ ๊ทธ๋ฆฌ๊ธฐ ๊ธฐ๋ฅ - ๋ชจ๋ฌ UI - ์ด๋ฏธ์ง ๋ก๋/์ ์ฅ - ํฐ์น ์ง์