I am developing a whiteboard application using react, node.js and socket.io. My requirement is when I open the whiteboard it will also visible to other people/user. How can I achieve that? In current situation user have to click on a button to open the whiteboard from ther end. I am new to react and socket.io. It will be very helpful if anybody share any knowledge about the idea.
I have shared some code done so far.
server.js
const express = require('express');
const app = express();
const path = require('path');
const http = require('http').createServer(app);
const io = require('socket.io')(http);
io.on('connection', onConnection);
function onConnection(socket){
socket.on('drawing', (data) => {
socket.broadcast.emit('drawing',data);
console.log(data);
});
socket.on('clear', () => {
socket.broadcast.emit('clear');
console.log('data cleard........');
});
}
app.get('*', (_, res) => res.sendFile(path.join(__dirname, 'build/index.html')));
const server_port = 8081;
http.listen(server_port, () => {
console.log(`Started on : ${server_port}`);
})
canvas.jsx
const Canvas = () => {
const canvasRef = useRef(null);
const colorsRef = useRef(null);
const socketRef = useRef();
const classes = useStyles();
const [color, setColor] = useState('#3B3B3B');
const [size, setSize] = useState('3');
const [cursor, setCursor] = useState('default');
const [isDrawing, setIsDrawing] = useState(false);
const timeout = useRef(null);
const ctx = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
ctx.current = canvas.getContext('2d');
//Resizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
//Load from locastorage
const canvasimg = localStorage.getItem('canvasimg');
if (canvasimg) {
var image = new Image();
ctx.current = canvas.getContext('2d');
image.onload = function() {
ctx.current.drawImage(image, 0, 0);
setIsDrawing(false);
};
image.src = canvasimg;
}
}, [ctx]);
useEffect(() => {
// // --------------- getContext() method returns a drawing context on the canvas-----
const canvas = canvasRef.current;
// const context = canvas.getContext('2d');
let drawing = false;
// ctx.current = context;
// ------------------------------- create the drawing ----------------------------
const drawLine = (x0, y0, x1, y1, emit) => {
ctx.current.beginPath();
ctx.current.moveTo(x0, y0);
ctx.current.lineTo(x1, y1);
ctx.current.strokeStyle = color;
ctx.current.lineWidth = size;
ctx.current.stroke();
ctx.current.closePath();
if (!emit) {
return;
}
const w = canvas.width;
const h = canvas.height;
socketRef.current.emit('drawing', {
x0: x0 / w,
y0: y0 / h,
x1: x1 / w,
y1: y1 / h,
});
};
// // ---------------- mouse movement --------------------------------------
const onMouseDown = e => {
drawing = true;
ctx.current.x = e.clientX || e.touches[0].clientX;
ctx.current.y = e.clientY || e.touches[0].clientY;
};
const onMouseMove = e => {
if (!drawing) {
return;
}
drawLine(
ctx.current.x,
ctx.current.y,
e.clientX || e.touches[0].clientX,
e.clientY || e.touches[0].clientY,
true
);
ctx.current.x = e.clientX || e.touches[0].clientX;
ctx.current.y = e.clientY || e.touches[0].clientY;
};
const onMouseUp = e => {
if (!drawing) {
return;
}
drawing = false;
drawLine(
ctx.current.x,
ctx.current.y,
e.clientX || e.touches[0].clientX,
e.clientY || e.touches[0].clientY,
true
);
};
// ----------- limit the number of events per second -----------------------
const throttle = (callback, delay) => {
let previousCall = new Date().getTime();
return function() {
const time = new Date().getTime();
if (time - previousCall >= delay) {
previousCall = time;
callback.apply(null, arguments);
}
};
};
// -----------------add event listeners to our canvas ----------------------
canvas.addEventListener('mousedown', onMouseDown, false);
canvas.addEventListener('mouseup', onMouseUp, false);
canvas.addEventListener('mouseout', onMouseUp, false);
canvas.addEventListener('mousemove', throttle(onMouseMove, 10), false);
// Touch support for mobile devices
canvas.addEventListener('touchstart', onMouseDown, false);
canvas.addEventListener('touchend', onMouseUp, false);
canvas.addEventListener('touchcancel', onMouseUp, false);
canvas.addEventListener('touchmove', throttle(onMouseMove, 10), false);
// -------------- make the canvas fill its parent component -----------------
const onResize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.addEventListener('resize', onResize, false);
onResize();
// ----------------------- socket.io connection ----------------------------
socketRef.current = io.connect('/');
const onDrawingEvent = data => {
const w = canvas.width;
const h = canvas.height;
drawLine(data.x0 * w, data.y0 * h, data.x1 * w, data.y1 * h);
};
socketRef.current.on('drawing', onDrawingEvent);
socketRef.current.on('clear', clearCanvas);
}, []);
const emitAndCanvas = () => {
socketRef.current.emit('clear');
clearCanvas();
};
const clearCanvas = () => {
// localStorage.removeItem('canvasimg');
const canvas = canvasRef.current;
const context = canvas.getContext('2d');
// ctx.current.fillStyle = 'white';
context.clearRect(0, 0, canvas.width, canvas.height);
// socketRef.current.emit('clear');
//Passing clear screen
};
const getPen = () => {
setCursor('default');
setSize('3');
setColor('#3B3B3B');
};
const eraseCanvas = () => {
setCursor('grab');
setSize('20');
setColor('#FFFFFF');
$('#circularcursor').show();
$(document).ready(function() {
$(document).on('mousemove', function(e) {
$('#circularcursor').css({
left: e.pageX,
top: e.pageY,
});
});
});
};
return (
<>
<p id="message">Initializing Sync...</p>
<div className="canvas-btn">
<button onClick={getPen} className="btn-width">
<Tooltip title="Pencil">
<CreateRoundedIcon />
</Tooltip>
</button>
<div className="btn-width">
<input type="color" value={color} onChange={e => setColor(e.target.value)} />
</div>
<div>
<Select value={size} onChange={e => setSize(e.target.value)}>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={10}>10</MenuItem>
<MenuItem value={15}>15</MenuItem>
<MenuItem value={20}>20</MenuItem>
<MenuItem value={25}>25</MenuItem>
</Select>
</div>
<div>
<button onClick={emitAndCanvas} className="btn-width">
<Tooltip title="Clear All">
<ClearAllIcon />
</Tooltip>
</button>
</div>
<div>
<button onClick={eraseCanvas} className="btn-width">
<Tooltip title="Reset">
<DeleteForeverRoundedIcon />
</Tooltip>
</button>
</div>
</div>
<canvas
style={{ cursor: cursor }}
// onMouseDown={onMouseMove}
// onMouseUp={onMouseUp}
// onMouseMove={drawLine}
ref={canvasRef}
className={classes.canvascover}
/>
</>
);
};
export default Canvas;