Created an online whiteboard within 30 minutes! HOW?
What is an online whiteboard?
It is an online writing or drawing tool, just like a board that we used to see in classes. We can write, draw anything on it. Online whiteboards can be used by many users simultaneously, sitting at a different geographical location but connected by the internet or some network with minimum latency. whenever a user draws/writes on it, is sent to all users, those who using/watching the same whiteboard, almost instantly.
Usecases: The Whiteboard is widely being used in online tutorials, live presentations, illustrations, or even while recording illustration or explanation videos. Probably the same idea is being used in google docs for collaborating many users on a file at the same time.
How do I develop one within half an hour?
I choose node.js as the server and used a few node.js libraries. The idea is to create events and broadcast data to everybody connected to that whiteboard, whenever someone draws something on it.
Source code is available on GitHub https://github.com/mukuldeep/real-time-whiteboard
Step 1: Install required libraries
- Install node if not already installed. official download link https://nodejs.org/en/download/
- create
mkdir directory_path_and_name
and move to the project directorycd directory_path
- install libraries express
npm install [email protected]
and socket.ionpm i socket.io
Step 2: create two files index.js
and whiteboard.html
inside that project folder, you created in the previous step.
Step 3: In whiteboard.html(will be sent and executed in clientside browsers), create a drawing pad using HTML5 canvas and related functions for capturing drawing information from that canvas. as described below
<!DOCTYPE html> <html> <body> <script> // creating canvas element and appending to document var canvas = document.createElement('canvas'); document.body.appendChild(canvas); //styles for the document and canvas document.body.style.margin = 0; canvas.style.position = 'fixed'; // canvas 2D context and resize var ctx = canvas.getContext('2d'); resize(); //initializing variables with last known position var pos = { x: 0, y: 0 }; //setting listeners for different actions window.addEventListener('resize', resize);// on resizing the window document.addEventListener('mousemove', draw); //mouse event move document.addEventListener('mousedown', setPosition);// mouse event down document.addEventListener('mouseenter', setPosition);//mouse event enter canvas.addEventListener('touchmove', draw,false);//touch event move canvas.addEventListener('touchstart', setPosition,false);//touch event start canvas.addEventListener('touchend', setPosition,false);//touch event end // new position from mouse event function setPosition(e) { pos.x = e.clientX; pos.y = e.clientY; } // resize canvas function resize() { ctx.canvas.width = window.innerWidth; ctx.canvas.height = window.innerHeight; } //capturing positions in canvas and drawing line between captured pair of points function draw(e) { // mouse left button must be pressed var msg=""; if (e.buttons !== 1) return; var x1,x2,y1,y2; console.log("from ("+pos.x+","+pos.y+")");//printing in console x1=pos.x;y1=pos.y;//from points setPosition(e); console.log("to ("+pos.x+","+pos.y+")");//printing in console x2=pos.x;y2=pos.y;//to points draw_line(x1,y1,x2,y2);//drawing line from from-points to to-points } //draws a line from one point to another point function draw_line(x1,y1,x2,y2){ ctx.beginPath(); // begin ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = '#c0392b'; ctx.moveTo(x1, y1); // from ctx.lineTo(x2, y2); // to ctx.stroke(); // draw it! } </script> </body> </html>
step 4: Add socket.io code to emit the data to server, add the library, initiate, then use emit, on methods. use .emit() to send data to server, .on() to listen messages from the server.
<!DOCTYPE html> <html> <body> <script src="/socket.io/socket.io.js"></script> <script> //socket init var socket = io(); // creating canvas element and appending to document var canvas = document.createElement('canvas'); document.body.appendChild(canvas); //styles for the document and canvas document.body.style.margin = 0; canvas.style.position = 'fixed'; // canvas 2D context and resize var ctx = canvas.getContext('2d'); resize(); //initializing variables with last known position var pos = { x: 0, y: 0 }; //setting listeners for different actions window.addEventListener('resize', resize);// on resizing the window document.addEventListener('mousemove', draw); //mouse event move document.addEventListener('mousedown', setPosition);// mouse event down document.addEventListener('mouseenter', setPosition);//mouse event enter canvas.addEventListener('touchmove', draw,false);//touch event move canvas.addEventListener('touchstart', setPosition,false);//touch event start canvas.addEventListener('touchend', setPosition,false);//touch event end // new position from mouse event function setPosition(e) { pos.x = e.clientX; pos.y = e.clientY; } // resize canvas function resize() { ctx.canvas.width = window.innerWidth; ctx.canvas.height = window.innerHeight; } //capturing positions in canvas and drawing line between captured pair of points function draw(e) { // mouse left button must be pressed var msg=""; if (e.buttons !== 1) return; var x1,x2,y1,y2; console.log("from ("+pos.x+","+pos.y+")");//printing in console x1=pos.x;y1=pos.y;//from points setPosition(e); console.log("to ("+pos.x+","+pos.y+")");//printing in console x2=pos.x;y2=pos.y;//to points //emitting message in the name of "board activity" var arr=[x1,y1,x2,y2]; socket.emit('board activity',arr); //draw_line(x1,y1,x2,y2);//drawing line from from-points to to-points } //draws a line from one point to another point function draw_line(x1,y1,x2,y2){ ctx.beginPath(); // begin ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = '#c0392b'; ctx.moveTo(x1, y1); // from ctx.lineTo(x2, y2); // to ctx.stroke(); // draw it! } //listening to socket event named "board activity" and drawing line accordingly socket.on('board activity', function(msg) { draw_line(msg[0],msg[1],msg[2],msg[3]); console.log(msg); }); </script> </body> </html>
step 5: set up serverside script. starting with importing required libraries and frameworks like express, socket.io, HTTP. create server and add logic for different operations.
//importing libraries const express = require('express'); const app = express(); const http = require('http'); const server = http.createServer(app); const { Server } = require("socket.io"); const io = new Server(server);//initializing server app.get('/', (req, res) => {//mapping client side file with url res.sendFile(__dirname + '/whiteboard.html'); }); //on events io.on('connection', (socket) => {//on connection console.log('a user connected'); socket.on('disconnect', () => {//on disconnect console.log('user disconnected'); }); socket.on('board activity', (msg) => {//on board activity //console.log('message: ' + msg); io.emit('board activity', msg);//broadcasting the board activity just received }); }); //listening to the port 3000 server.listen(3000, () => { console.log('listening on *:3000'); });
step 6: READY to explode.
run the application node index.js
open the link like http://localhost:3000 in the browser in multiple tabs and try drawing my face in one of them LOL.
HAPPY DRAWING đ
Source code is available on GitHub https://github.com/mukuldeep/real-time-whiteboard
Code is explained line by line using comments, if you have doubt or difficulty understanding the codes let me know in the comment section.
Recent Comments