Painting together with Socket.io

Color: Brush: Size:

Draw strokes on the canvas above and use the control panel for changing the stroke.
All the drawing information is sent to other clients. You can try it by opening another tab.

Used code and knowledge from:

Nodejs code at the server

1
2
3
4
5
6
7
8
9
10
11
var io = require('socket.io')(8000);
//set a namespace.
var mandala = io.of('/mandala');
// Listen for a new client.
mandala.on('connection', function (socket) {
  // Listen on senddrawing events.
  socket.on('senddrawing', function (data) {
    // Send a drawing event with the data to all the other clients than the original one.
    socket.broadcast.emit('drawing',data);
  });
});

Javascript at the client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * Used code and knowledge from:
 * https://developer.mozilla.org
 * http://www.w3schools.com
 * http://tutorialzine.com/2012/08/nodejs-drawing-game/
 * 
*/
// Get the canvas element of the document.
var canvas = document.getElementById("canvas");
// Get the 2d Context of the canvas.
var ctx = canvas.getContext("2d");
// Get the color picker element of the document.
var colorPicker = document.getElementById("color");
// Get the brush element of the document.
var brushPicker = document.getElementById("brush");
// Get the brush element of the document.
var sizePicker = document.getElementById("size");
// mousedown is used for tracking if the user is holding the mouse down
var mousedown = false;
// Using web sockets and port 8000 for openshift.
var url = 'https://hartwin.hoyer.xyz/socket.io/mandala';
// connecting io
var socket = io.connect(url);
// clientData is going to have the "from" and "to" coordinates of a single stroke
var clientData = {
  oldx : 0,
  oldy : 0,
  x : 0,
  y : 0,
  color : colorPicker.value,
  brush : brushPicker.value,
  size : sizePicker.value
};
var brush = {};
  
// updating the mouse coordinates. The old values are used for the "from" values.
function updateclientData(canvas, e) {
  var BoundingClientRect = canvas.getBoundingClientRect();
  clientData.oldx = clientData.x;
  clientData.oldy = clientData.y;
  clientData.x = e.clientX - BoundingClientRect.left;
  clientData.y = e.clientY - BoundingClientRect.top;
  clientData.color = colorPicker.value;
  clientData.brush = brushPicker.value;
  clientData.size = sizePicker.value;
}

// When the mouse button is down, update the mouse position. Since this is the beginning of a stroke, the old values are the same as the new ones.
canvas.addEventListener('mousedown', function (e) {
  mousedown = true;
  updateclientData(canvas, e);
  clientData.oldx = clientData.x;
  clientData.oldy = clientData.y;
}, false);

// The mouse button is released.
canvas.addEventListener('mouseup', function (e) {
	mousedown = false;
}, false);

// The mouse is moving over the canvas. When the mouse button is down, send the position and the color to the server.
canvas.addEventListener('mousemove', function (e) {
  if (mousedown === true) {
    updateclientData(canvas, e);
    // send the position and the color to the server.
    socket.emit('senddrawing', clientData, colorPicker.value,brush.value);
    // the data is only sent to other clients. So this client draws it with its own data.
    draw(clientData, colorPicker.value, brush.value);
  }
}, false);

// listen for a 'drawing' event and draw with the received data.
socket.on('drawing', function (data) {
  draw(data);
});

function draw(data){
  brush[data.brush](data);
}

// Draw a freehand line
brush.stroke = function(data) {
  // Start a new path. This enables a colorchange for each stroke and user.
  ctx.beginPath();
  ctx.lineWidth=data.size;
  ctx.strokeStyle = data.color;
  ctx.lineCap="round";
  ctx.moveTo(data.oldx, data.oldy);
  ctx.lineTo(data.x, data.y);
  ctx.stroke();
}

// Draw filled squares
brush.square = function(data) {
  // Start a new path. This enables a colorchange for each stroke and user.
  ctx.beginPath();
  ctx.fillStyle=data.color;
  ctx.fillRect(data.x-data.size/2,data.y-data.size/2,data.size,data.size); 
}

// Draw filled circles
brush.square = function(data) {
  // Start a new path. This enables a colorchange for each stroke and user.
  ctx.beginPath();
  ctx.fillStyle=data.color;
  ctx.fillRect(data.x-data.size/2,data.y-data.size/2,data.size,data.size); 
}

// Spray pixels
brush.spray = function(data) {
  var density = 10;
  var size = data.size;
  var x = 0;
  var y = 0;
  for (var i = 0; i <= density; i++){
    x = data.oldx + Math.floor((Math.random() * size*2) - size + 1);
    y = data.oldy + Math.floor((Math.random() * size*2) - size + 1);
    ctx.beginPath();
    ctx.fillStyle=data.color;
    ctx.fillRect(x,y,1,1); 
  }
}