Overnap

캔버스 그림 통신 구현

1 -import React, { useCallback, useEffect, useRef, useState } from 'react'; 1 +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
2 -import { Vector } from './types'; 2 +import SocketContext from '../../contexts/SocketContext';
3 +import { MessageType, RawMessage } from '../common/types';
4 +import { BrushData, Vector } from './types';
3 5
4 // 참고 : https://basketdeveloper.tistory.com/79 6 // 참고 : https://basketdeveloper.tistory.com/79
5 7
...@@ -8,6 +10,7 @@ interface CanvasProps { ...@@ -8,6 +10,7 @@ interface CanvasProps {
8 } 10 }
9 11
10 export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => { 12 export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => {
13 + const socket = useContext(SocketContext);
11 const canvasRef = useRef<HTMLCanvasElement>(null); 14 const canvasRef = useRef<HTMLCanvasElement>(null);
12 15
13 const [mousePosition, setMousePosition] = useState<Vector>({ x:0, y:0 }); 16 const [mousePosition, setMousePosition] = useState<Vector>({ x:0, y:0 });
...@@ -56,6 +59,22 @@ export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => { ...@@ -56,6 +59,22 @@ export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => {
56 if (coordinates) { 59 if (coordinates) {
57 setIsPainting(true); 60 setIsPainting(true);
58 setMousePosition(coordinates); 61 setMousePosition(coordinates);
62 +
63 + const rawMessage: RawMessage = {
64 + type: MessageType.DRAW_MOVE,
65 + message: coordinates
66 + };
67 + socket.emit('msg', rawMessage, () => {});
68 +
69 + const nextRawMessage: RawMessage = {
70 + type: MessageType.DRAW_SET,
71 + message: {
72 + size: 5,
73 + color: '000000',
74 + drawing: true
75 + } as BrushData
76 + };
77 + socket.emit('msg', nextRawMessage, () => {});
59 } 78 }
60 }, []); 79 }, []);
61 80
...@@ -69,6 +88,13 @@ export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => { ...@@ -69,6 +88,13 @@ export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => {
69 const newMousePosition = getCoordinates(event); 88 const newMousePosition = getCoordinates(event);
70 if (mousePosition && newMousePosition) { 89 if (mousePosition && newMousePosition) {
71 drawLine(mousePosition, newMousePosition); 90 drawLine(mousePosition, newMousePosition);
91 +
92 + const rawMessage: RawMessage = {
93 + type: MessageType.DRAW_MOVE,
94 + message: newMousePosition
95 + };
96 + socket.emit('msg', rawMessage, () => {});
97 +
72 setMousePosition(newMousePosition); 98 setMousePosition(newMousePosition);
73 } 99 }
74 } 100 }
...@@ -77,32 +103,86 @@ export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => { ...@@ -77,32 +103,86 @@ export const Canvas: React.FC<CanvasProps> = ({ isDrawer }) => {
77 ); 103 );
78 104
79 const exitPaint = useCallback(() => { 105 const exitPaint = useCallback(() => {
106 + const rawMessage: RawMessage = {
107 + type: MessageType.DRAW_SET,
108 + message: {
109 + size: 5,
110 + color: '000000',
111 + drawing: false
112 + } as BrushData
113 + };
114 + socket.emit('msg', rawMessage, () => {});
115 +
80 setIsPainting(false); 116 setIsPainting(false);
81 }, []); 117 }, []);
82 118
119 + const handleDrawSet = useCallback((rawMessage: RawMessage) => {
120 + if (rawMessage.type === MessageType.DRAW_SET) {
121 + const data = rawMessage.message as BrushData;
122 + setIsPainting(data.drawing);
123 + }
124 + }, []);
125 +
126 + const handleDrawMove = useCallback((rawMessage: RawMessage) => {
127 + if (rawMessage.type === MessageType.DRAW_MOVE) {
128 + const data = rawMessage.message as Vector;
129 + if (isPainting) {
130 + drawLine(mousePosition, data);
131 + }
132 + setMousePosition(data);
133 + }
134 + }, [isPainting, mousePosition])
135 +
83 useEffect(() => { 136 useEffect(() => {
84 - if (canvasRef.current && isDrawer) { 137 + if (canvasRef.current) {
85 - const canvas: HTMLCanvasElement = canvasRef.current; 138 + if (isDrawer) {
139 + const canvas: HTMLCanvasElement = canvasRef.current;
86 140
87 - canvas.addEventListener('mousedown', startPaint); 141 + canvas.addEventListener('mousedown', startPaint);
88 - canvas.addEventListener('mousemove', paint); 142 + canvas.addEventListener('mousemove', paint);
89 - canvas.addEventListener('mouseup', exitPaint); 143 + canvas.addEventListener('mouseup', exitPaint);
90 - canvas.addEventListener('mouseleave', exitPaint); 144 + canvas.addEventListener('mouseleave', exitPaint);
91 - 145 +
92 - return () => { 146 + return () => {
93 - canvas.removeEventListener('mousedown', startPaint); 147 + canvas.removeEventListener('mousedown', startPaint);
94 - canvas.removeEventListener('mousemove', paint); 148 + canvas.removeEventListener('mousemove', paint);
95 - canvas.removeEventListener('mouseup', exitPaint); 149 + canvas.removeEventListener('mouseup', exitPaint);
96 - canvas.removeEventListener('mouseleave', exitPaint); 150 + canvas.removeEventListener('mouseleave', exitPaint);
97 - }; 151 + };
98 - } else { 152 + }
99 - // 받아서 그리기
100 } 153 }
101 }, [isDrawer, startPaint, paint, exitPaint]); 154 }, [isDrawer, startPaint, paint, exitPaint]);
102 155
156 + useEffect(() => {
157 + if (!isDrawer) {
158 + socket.on('msg', handleDrawSet);
159 + socket.on('msg', handleDrawMove);
160 +
161 + return () => {
162 + socket.off('msg', handleDrawSet);
163 + socket.off('msg', handleDrawMove);
164 + }
165 + }
166 + }, [isDrawer, handleDrawMove]);
167 +
168 + const handleClearWhenStart = useCallback((rawMessage: RawMessage) => {
169 + if (rawMessage.type === MessageType.GAME_START) {
170 + clearCanvas();
171 + setIsPainting(false);
172 + // TODO: 펜 굵기, 색 설정하게 되면 여기에 초기화 넣기
173 + }
174 + }, []);
175 +
176 + useEffect(() => {
177 + socket.on('msg', handleClearWhenStart);
178 + return () => {
179 + socket.off('msg', handleClearWhenStart);
180 + }
181 + }, []);
182 +
103 return ( 183 return (
104 <div className='mx-3 px-2 py-1 rounded shadow'> 184 <div className='mx-3 px-2 py-1 rounded shadow'>
105 - <canvas ref={canvasRef} width='512' height='384' /> 185 + <canvas ref={canvasRef} width='640' height='480' />
106 </div> 186 </div>
107 ); 187 );
108 } 188 }
...\ No newline at end of file ...\ No newline at end of file
......