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 directory cd directory_path
  • install libraries express npm install [email protected] and socket.io npm 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.

You may also like...

Leave a Reply

Your email address will not be published.