3

Building a multiplayer doodle using fabric js.

Trying to implement multiplayer doodle using fabric js, the idea is when U1 draws on canvas we push the points to RTDB and get those points on both the client and programmatically draw the stroke in both the clients.

Kushagra Agarwal
  • 1,816
  • 7
  • 18
  • 31
  • 2
    Does this answer your question? [Emulate free drawing with fabricjs](https://stackoverflow.com/questions/40595783/emulate-free-drawing-with-fabricjs) – Mosh Feu Feb 12 '20 at 15:34
  • this is a hack but it works, problem occurs when there are huge amount of events it slows down the device or results in a hung web page. – Kushagra Agarwal Feb 13 '20 at 11:40

1 Answers1

7

You can save the canvas' data on path:created for example (or other event) using toJSON().
Send it to the server and the other client will load it using loadFromJSON().

Update (4.3.1) (Thanks to @user8555937)

const pointer = canvas.getPointer(e);
const options = {pointer, e:{}} // required for Fabric 4.3.1

canvas2.freeDrawingBrush.onMouseDown(pointer, options);

var canvas = new fabric.Canvas(document.getElementById('canvasId'))
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.width = 5;
canvas.freeDrawingBrush.color = '#00aeff';

canvas.on('path:created', function(e) {
  e.path.set();
  canvas.renderAll();
  drawOnCanvas(canvas.toJSON());
});

var canvas2 = new fabric.Canvas(document.getElementById('canvasId2'));
function drawOnCanvas(json) {
  canvas2.loadFromJSON(json);
}
#app {
  display: flex;  
}

canvas {
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>

<div id="app">
  <canvas id="canvasId" width="400" height="400"></canvas>
  <canvas id="canvasId2" width="400" height="400"></canvas>
</div>

Probably you can optimize it by sending only the diffs and so on, but this is the start of the path

Sync on drawing (not only after path:created)

The idea is to "capture" the "original" canvas' events and trigger them on the second one.
So, you can send the pointer to the server and trigger the events in the other clients.

var canvas = new fabric.Canvas(document.getElementById('canvasId'))
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.width = 5;
canvas.freeDrawingBrush.color = '#00aeff';

let isDrawing = false;
canvas.on('mouse:down', function({e}) {
  isDrawing = true;
  onMouseDown(e);
}).on('mouse:up', function({e}) {
  isDrawing = false;
  onMouseUp(e);
}).on('mouse:move', function({e}) {
  if (isDrawing) {
    const pointer = canvas.getPointer(e);
    drawRealTime(e, pointer);
  }
});

var canvas2 = new fabric.Canvas(document.getElementById('canvasId2'));
canvas2.isDrawingMode = true;
canvas2.freeDrawingBrush.width = 5;
canvas2.freeDrawingBrush.color = '#00aeff';

function onMouseDown(e) {
  const pointer = canvas.getPointer(e);
  canvas2.freeDrawingBrush.onMouseDown(pointer);
}

function onMouseUp(e) {
  const pointer = canvas.getPointer(e);
  canvas2.freeDrawingBrush.onMouseUp(pointer);
}

function drawRealTime(e, pointer) {
  canvas2.freeDrawingBrush.onMouseMove(pointer);
}
#app {
  display: flex;  
}

canvas {
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>

<div id="app">
  <canvas id="canvasId" width="400" height="400"></canvas>
  <canvas id="canvasId2" width="400" height="400"></canvas>
</div>

https://codepen.io/moshfeu/pen/ZEGQEBO?editors=0010

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
  • That's an excellent approach and we were on a similar path but we want real time updates like when user is drawing it in one client the same effect reflects on the other client and not just when the stroke is complete also it needs to be two way. Same if we add a sticker and move it around – Kushagra Agarwal Feb 13 '20 at 13:06
  • I updated my answer (and the codepen) - added an example for "real time" drawing. Take a look. – Mosh Feu Feb 13 '20 at 16:21
  • @KushagraAgarwal what do you think? – Mosh Feu Feb 22 '20 at 16:44
  • It works but both the user/canvas should have the ability to draw, i.e is the pain point – Kushagra Agarwal Feb 27 '20 at 07:04
  • 3
    Do you want me to write you app? It's a different price :) You can continue with the answer's direction to implement it both ways. – Mosh Feu Feb 27 '20 at 09:37
  • haha sure man would love to get you on board but we already made it live taking a different approach thanks for your help – Kushagra Agarwal Feb 27 '20 at 10:27
  • Interesting. You can put that approach here is an answer. It could help to other people (Also,I'm curious :)). – Mosh Feu Feb 27 '20 at 10:39
  • Actually implemented this with plain canvas api and ditched fabric completely. Can share it here but it will be irrelevant for this question – Kushagra Agarwal Feb 27 '20 at 11:25
  • You're right, it's not relevant to this question. If you would write a post about it, I'll love to read it. – Mosh Feu Feb 27 '20 at 11:41