Advance Demo: demos/dashboard/
Multiple designers demo: https://www.webrtc-experiment.com/Canvas-Designer/multiple.html
"Collaborative" Canvas Designer i.e. Canvas-Drawing tool allows you draw bezier/quadratic curves, rectangles, circles and lines. You can also set strokes, back/forth colors and much more. You can draw using pencils, erase drawing, type texts etc. You can easily add your own tools.
You can check all releases here:
The specialty of this drawing-tool is that, it generates Canvas2D code for you; so simply draw and get the code! That code can be used in any javascript Canvas2D application.
You can submit issues here:
Also, you can collaborate your drawing with up to 15 users; and everything is synced from all users. So, if you draw a line and your friend-A draws quadratic curve and friend-B draws rectangle then everything will be synced among all users!
Gif images:
You can use designer.setSelected or designer.setTools for below tools.
line--- to draw straight linespencil--- to write/draw shapesdragSingle--- to drag/ove and especially resize last selected shapedragMultiple--- to drag/move all shapeseraser--- to erase/clear specific portion of shapesrectangle--- to draw rectanglesarc--- to draw circlesbezier--- to draw bezier curvesquadratic--- to draw quadratic curvestext--- to write texts on single or multiple lines, select font families/sizes and moreimage--- add external imagesarrow--- draw arrow linesmarker--- draw markerslineWidth--- set line widthcolorsPicker--- background and foreground colors pickerextraOptions--- extra options eg. lineCap, lineJoin, globalAlpha, globalCompositeOperation etc.pdf--- to import PDFcode--- to enable/disable code viewundo--- undo recent shapes
The correct name for dragSingle should be: drag-move-resize last-selected-shape.
The correct name for dragMultiple should be: drag-move all-shapes.
- Allow users to add video-streams or screen-streams or existing-webm-mp4-videos
- Resize all shapes at once (currently you can resize last selected shape only)
-
Draw single or multiple shapes of any kind (according to toolbox)
-
Drag/resize/adjust all the shapes in any possible direction
-
Rectangles and images can be resized in 4-directions
Red transparent small circles helps you understand how to resize.
-
Undo drawings using
ctrl+zkeys (undo all shapes, undo last 10 or specific shapes, undo range of shapes or undo last shape) -
Drag/move single or all the shapes without affecting any single coordinate
More importantly, you can use unlimited designers on a single page. Each will have its own surface and its own tools.
You can install following chrome extension for multi-language input tools:
Now type your own language text in any <input> box or anywhere, and simply copy that text.
Now click T tool icon from the tool-box and press ctrl+v to paste your own language's text.
To repeat it:
- Type your own language texts anywhere and make sure to copy to clipboard using
ctrl+v - Then click
Ticon, and then pressctrl+vto paste your copied text
You can paste any text: English, Arabic, Chinese etc.
-
Download/link
canvas-designer-widget.jsfrom this github repository. -
Set
designer.widgetHtmlURLanddesigner.widgetJsURLin your HTML file. -
Use this command to append widget in your HTML page:
var designer = new CanvasDesigner();designer.appendTo(document.body);
<!-- 1st step -->
<script src="https://www.webrtc-experiment.com/Canvas-Designer/canvas-designer-widget.js"></script>
<!-- 2nd step -->
<script>
var designer = new CanvasDesigner();
// both links are mandatory
// widget.html will internally use widget.js
designer.widgetHtmlURL = 'https://www.webrtc-experiment.com/Canvas-Designer/widget.html'; // you can place this file anywhere
designer.widgetJsURL = 'https://www.webrtc-experiment.com/Canvas-Designer/widget.js'; // you can place this file anywhere
</script>
<!-- 3rd i.e. last step -->
<script>
// <iframe> will be appended to "document.body"
designer.appendTo(document.body || document.documentElement);
</script>var designer = new CanvasDesigner();
websocket.onmessage = function(event) {
designer.syncData( JSON.parse(event.data) );
};
designer.addSyncListener(function(data) {
websocket.send(JSON.stringify(data));
});
designer.setSelected('pencil');
designer.setTools({
pencil: true,
text: true
});
designer.appendTo(document.documentElement);It is having designer.destroy() method as well.
Use WebRTC!
webrtc.onmessage = function(event) {
designer.syncData( event.data );
};
designer.addSyncListener(function(data) {
webrtc.send(data);
});socket.on('message', function(data) {
designer.syncData( data );
});
designer.addSyncListener(function(data) {
socket.emit('message', data);
});You can place widget.html file anywhere on your site.
designer.widgetHtmlURL = '/html-files/widget.html';By default widget.html is placed in the same directory of index.html.
// here is default value
designer.widgetHtmlURL = 'widget.html';Remember, widget.html is loaded using <iframe>.
Note: This file is internally used by
widget.html.
You can place widget.html file anywhere on your site.
designer.widgetJsURL = '/js-files/widget.min.js';By default widget.min.js is placed in the same directory of index.html.
// here is default value
designer.widgetJsURL = 'widget.min.js';Remember, widget.js is loaded using <iframe>.
Pass array-of-points that are shared by remote users using socket.io or websockets or XMPP or WebRTC.
designer.syncData(arrayOfPoints);An example to pass custom data on Canvas-Designer:
var x = 0;
var y = 0;
var width = designer.iframe.clientWidth;
var height = designer.iframe.clientHeight;
var image = 'https://www.webrtc-experiment.com/images/RTCMultiConnection-STUN-TURN-usage.png';
var points = [
['image', [image, x, y, width, height, 1], ['2', '#6c96c8', 'rgba(0,0,0,0)', '1', 'source-over', 'round', 'round', '15px "Arial"']]
];
designer.syncData({
startIndex: 0,
points: points
});Remove and clear all drawings from the canvas:
designer.clearCanvas();Call this method internally to fix video rendering issues.
designer.renderStream();This callback is invoked as soon as something new is drawn. An array-of-points is passed over this function. That array MUST be shared with remote users for collaboration.
designer.addSyncListener(function(data) {
designer.send(JSON.stringify(data));
});This method allows you select specific tools.
- See list of all tools
designer.setSelected('rectangle');This method allows you choose between tools that should be displayed in the tools-panel.
- See list of all tools
designer.setTools({
line: true,
arrow: true,
pencil: true,
marker: true,
dragSingle: true,
dragMultiple: true,
eraser: true,
rectangle: true,
arc: true,
bezier: true,
quadratic: true,
text: true,
image: true,
pdf: true,
zoom: true,
lineWidth: true,
colorsPicker: true,
extraOptions: true,
code: true,
undo: true
});You can force/set your own tool-icons:
designer.icons = {
line: '/icons/line.png',
arrow: '/icons/arrow.png',
pencil: '/icons/pencil.png',
dragSingle: '/icons/dragSingle.png',
dragMultiple: '/icons/dragMultiple.png',
eraser: '/icons/eraser.png',
rectangle: '/icons/rectangle.png',
arc: '/icons/arc.png',
bezier: '/icons/bezier.png',
quadratic: '/icons/quadratic.png',
text: '/icons/text.png',
image: '/icons/image.png',
pdf: '/icons/pdf.png',
pdf_next: '/icons/pdf-next.png',
pdf_prev: '/icons/pdf-prev.png',
marker: '/icons/marker.png',
zoom: '/icons/zoom.png',
lineWidth: '/icons/lineWidth.png',
colorsPicker: '/icons/colorsPicker.png',
extraOptions: '/icons/extraOptions.png',
code: '/icons/code.png'
};You can set like this as well:
designer.icons.line = '/icons/line.png';Default values are NULL to force icons from /dev/data-dris.js.
CanvasDesigner is a widget; that widget should be appended to a DOM object. This method allows you pass <body> or any other HTMLDOMElement.
designer.appendTo(document.body || document.documentElement);
// or
designer.appendTo(document.body || document.documentElement, function() {
alert('iframe load callback');
});The correct name for appendTo is: append-iframe to target HTML-DOM-element
If you want to remove the widget from your HTMLDOMElement.
designer.destroy();You can access designer iframe as following:
designer.iframe.style.border = '5px solid red';
window.open(designer.iframe.src);designer.iframe will be null/undefined until you call appendTo. So always use this code-block:
if(!designer.iframe) {
designer.appendTo(document.body);
}
designer.iframe.style.border = '5px solid red';Get data-URL of your drawings!
designer.toDataURL('image/png', function(dataURL) {
window.open(dataURL);
});You can manually sync drawings by invoking designer.sync method:
designer.sync();Here is a real usecase:
webrtcDataChannel.onopen = function() {
if(designer.pointsLength > 0) {
// you seems having data to be synced with new user!
designer.sync();
}
};Get MediaStream object and share in realtime using RTCPeerConnection.addStream API.
<script src="dev/webrtc-handler.js"></script>
<script>
designer.captureStream(function(stream) {
var url = URL.createObjectURL(stream);
videoPreview.src = url;
rtcPeerConnection.addStream(stream);
rtcPeerConnection.createOffer(success, failure, params);
});
</script>Each shape is considered as a point. This value allows you check number of shapes that are already drawn on the canvas-designer.
(function looper() {
document.getElementById('number-of-shapes').inenrHTML = designer.pointsLength;
setTimeout(looper, 1000);
})();Or a real usage:
websocket.onopen = function() {
if(designer.pointsLength > 0) {
// you seems having data to be synced with existing users!
designer.sync();
}
};You can either undo drawings by pressing ctrl+z on windows and command+z on Mac; however you can undo using designer.undo method as well:
designer.undo(); // undo last shape
designer.undo(-1); // undo last shape
// undo shape from specific index
designer.undo(0);
// undo all shapes
designer.undo('all');
// undo last 10 shapes
designer.undo({
numberOfLastShapes: 10
})
// to remove all occurrences of a specific shape
designer.undo('pencil');
designer.undo('arrow');
designer.undo('rect');designer.pointsLength shows number of shapes; and designer.undo accepts shape-index as well.
Open widget.html and add your new tool-icon HTML.
<div id="tool-box" class="tool-box"> <!-- search for this div; and include your HTML inside this div -->
<canvas id="yourNewToolIcon" width="40" height="40"></canvas> <!-- here is your icon-HTML -->
</div>Open decorator.js and decorate your new HTML icon.
var tools = {
yourNewToolIcon: true // add this line to make sure index.html can use it
};Search for decorateLine method, and append following snippet quickly after that method:
function decorateYourNewToolIcon() {
var context = getContext('yourNewToolIcon');
context.fillStyle = 'Gray';
context.font = '9px Verdana';
context.fillText('New', 16, 12);
bindEvent(context, 'YourNewToolIconSelected');
}
if (tools.yourNewToolIcon === true) {
decorateYourNewToolIcon();
} else document.getElementById('yourNewToolIcon').style.display = 'none';Open common.js and add selection-states for your new tool-icon (i.e. whether your new tool icon is selected or not):
var is = {
isYourNewToolIconSelected: false, // add this line
set: function (shape) {
var cache = this;
cache.isYourNewToolIconSelected = false; // add this line as well.
// ..... don't modify anything else
cache['is' + shape] = true;
}
};You merely need to set isYourNewToolIconSelected:true also cache.isYourNewToolIconSelected=false.
Create new file in the dev directory. Name this file as yourNewToolIcon-handler.js.
This file MUST look like this:
var yourNewToolIconHandler = {
ismousedown: false,
mousedown: function(e) {
this.ismousedown = true;
},
mouseup: function(e) {
this.ismousedown = false;
},
mousemove: function(e) {
if(this.ismousedown) { ... }
}
};You can check other *-handler.js from dev directory to get the idea how exactly it works.
Now open Gruntfile.js#L43 and add link to your new file: dev/events-handler.js.
Now compile all your changes using grunt.
Open events-handler.js and make sure that your above yourNewToolIconHandler object is called for mouse up/down/move events.
addEvent(canvas, isTouch ? 'touchstart' : 'mousedown', function (e) {
// you merely need to add this line at the end of this method
else if (is.isYourNewToolIconSelected) yourNewToolIconHandler.mousedown(e);
});
addEvent(document, isTouch ? 'touchend' : 'mouseup', function (e) {
// you merely need to add this line at the end of this method
else if (is.isYourNewToolIconSelected) yourNewToolIconHandler.mouseup(e);
});
addEvent(canvas, isTouch ? 'touchmove' : 'mousemove', function (e) {
// you merely need to add this line at the end of this method
else if (is.isYourNewToolIconSelected) yourNewToolIconHandler.mousemove(e);
});First of all, we are checking whether your tool-icon is selected or not: is.isYourNewToolIconSelected
Then we are calling yourNewToolIconHandler dot mousedown/mouseup/mousemove events respectively.
Open draw-helper.js. Make sure that your new tool-icon can be drawn on the <canvas> surface.
yourNewToolIcon: function(context, point, options) {
context.beginPath();
context.moveTo(point[0], point[1]);
context.whateverYouWantToDoHere(point[2], point[3]);
this.handleOptions(context, options);
}Usually point[0] is x coordinates; point[1] is y coordinates; point[2] is width and point[3] is height.
Different shapes can handle these points differently.
There is NO-limit for point[index]. You can add as many points as you want.
Complex shapes can add 10 or 20 points.
Open drag-helper.js and make sure that your new shape can be dragged/resized/move.
Search for p[0] === 'line' and add similar code-blocks for your shape (new-tool-icon) as well.
Open common.js and make sure that your new shape (tool-icon) is printed on the <textarea> as well.
This allows end-users to copy your shape's code and use anywhere on their own web-pages.
Open common.js file; there is a function updateTextArea inside the "common" object – which is aimed to output into textarea element.
You don't have to change updateTextArea. For simplicity purpose, code is separated in different functions/properties that you've to edit:
Search for p[0] === 'line' and add similar code-blocks for your shape (new-tool-icon) as well.
ctrl+t (to display text-fonts box)
ctrl+z (to undo last-single shape)
ctrl+a (to select all shapes)
ctrl+c (copy last-selected shape)
ctrl+v (paste last-copied shape)
ctrl+mousedown allows you quickly copy/paste all shapes. (i.e. ctrl button + mouse down)
Please make pull-request to update this list.
Canvas Designer is released under MIT license . Copyright (c) Muaz Khan.

