canvas-designer

Collaborative, extendable, JavaScript Canvas2D drawing tool, supporting dozens of builtin tools, as well as generates JavaScript code for 2D animations.

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
canvas-designer
1.3.05 years ago8 years agoMinified + gzip package size for canvas-designer in KB

Readme

Demo: https://www.webrtc-experiment.com/Canvas-Designer/

Advance Demo: demos/dashboard/

Multiple designers demo: https://www.webrtc-experiment.com/Canvas-Designer/multiple.html

YouTube video:

  • https://www.youtube.com/watch?v=pvAj5lv3cM
npm downloads Build Status: Linux
"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:
  • https://github.com/muaz-khan/Canvas-Designer/releases
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:
  • https://github.com/muaz-khan/Canvas-Designer/issues
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!

Youtube Videos

  • https://www.youtube.com/watch?v=oSSwMlBu8SY
Gif images:
  • https://cdn.webrtc-experiment.com/images/Canvas-Designer.gif
Built-in tools
You can use designer.setSelected or designer.setTools for below tools.
  1. line --- to draw straight lines
  1. pencil --- to write/draw shapes
  1. dragSingle --- to drag/ove and especially resize last selected shape
  1. dragMultiple --- to drag/move all shapes
  1. eraser --- to erase/clear specific portion of shapes
  1. rectangle --- to draw rectangles
  1. arc --- to draw circles
  1. bezier --- to draw bezier curves
  1. quadratic --- to draw quadratic curves
  1. text --- to write texts on single or multiple lines, select font families/sizes and more
  1. image --- add external images
  1. arrow --- draw arrow lines
  1. marker --- draw markers
  1. lineWidth --- set line width
  1. colorsPicker --- background and foreground colors picker
  1. extraOptions --- extra options eg. lineCap, lineJoin, globalAlpha, globalCompositeOperation etc.
  1. pdf --- to import PDF
  1. code --- to enable/disable code view
  1. undo --- 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.

Upcoming tools

  1. Allow users to add video-streams or screen-streams or existing-webm-mp4-videos
  1. Resize all shapes at once (currently you can resize last selected shape only)
Features
  1. Draw single or multiple shapes of any kind (according to toolbox)
  1. Drag/resize/adjust all the shapes in any possible direction
  1. Rectangles and images can be resized in 4-directions
Red transparent small circles helps you understand how to resize.
  1. Undo drawings using ctrl+z keys (undo all shapes, undo last 10 or specific shapes, undo range of shapes or undo last shape)
  1. 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.
Chinese, Arabic, other languages
You can install following chrome extension for multi-language input tools:
  • https://chrome.google.com/webstore/detail/google-input-tools/mclkkofklkfljcocdinagocijmpgbhab?hl=en
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:
  1. Type your own language texts anywhere and make sure to copy to clipboard using ctrl+v
  1. Then click T icon, and then press ctrl+v to paste your copied text
You can paste any text: English, Arabic, Chinese etc.
How to Use
  1. Download/link canvas-designer-widget.js from this github repository.
  1. Set designer.widgetHtmlURL and designer.widgetJsURL in your HTML file.
  1. Use this command to append widget in your HTML page:
`var designer = new CanvasDesigner();`
`designer.appendTo(document.body);`
```html ``` You can even download TAR: ``` mkdir Canvas-Designer && cd Canvas-Designer wget http://dl.webrtc-experiment.com/canvas-designer.tar.gz tar -zxvf canvas-designer.tar.gz ls -a ```
Complete Usage
```javascript 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!
```javascript webrtc.onmessage = function(event) {
designer.syncData( event.data );
}; designer.addSyncListener(function(data) {
webrtc.send(data);
}); ```
Use Socket.io
```javascript socket.on('message', function(data) {
designer.syncData( data );
}); designer.addSyncListener(function(data) {
socket.emit('message', data);
}); ```
API Reference

widgetHtmlURL

You can place widget.html file anywhere on your site. ```javascript designer.widgetHtmlURL = '/html-files/widget.html'; ``` By default widget.html is placed in the same directory of index.html. ```javascript // here is default value designer.widgetHtmlURL = 'widget.html'; ``` Remember, widget.html is loaded using <iframe>.

widgetJsURL

Note: This file is internally used by widget.html.
You can place widget.html file anywhere on your site. ```javascript designer.widgetJsURL = '/js-files/widget.min.js'; ``` By default widget.min.js is placed in the same directory of index.html. ```javascript // here is default value designer.widgetJsURL = 'widget.min.js'; ``` Remember, widget.js is loaded using <iframe>.

syncData

Pass array-of-points that are shared by remote users using socket.io or websockets or XMPP or WebRTC. ```javascript designer.syncData(arrayOfPoints); ```

clearCanvas

Remove and clear all drawings from the canvas: ```javascript designer.clearCanvas(); ```

renderStream

Call this method internally to fix video rendering issues. ```javascript designer.renderStream(); ```

addSyncListener

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. ```javascript designer.addSyncListener(function(data) {
designer.send(JSON.stringify(data));
}); ```

setSelected

This method allows you select specific tools. ```javascript designer.setSelected('rectangle'); ```

setTools

This method allows you choose between tools that should be displayed in the tools-panel. ```javascript 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
}); ```

icons

You can force/set your own tool-icons: ```javascript 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: ```javascript designer.icons.line = '/icons/line.png'; ``` Default values are NULL to force icons from /dev/data-dris.js.

appendTo

CanvasDesigner is a widget; that widget should be appended to a DOM object. This method allows you pass <body> or any other HTMLDOMElement. ```javascript 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

destroy

If you want to remove the widget from your HTMLDOMElement. ```javascript designer.destroy(); ```

iframe

You can access designer iframe as following: ```javascript 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: ```javascript if(!designer.iframe) {
designer.appendTo(document.body);
} designer.iframe.style.border = '5px solid red'; ```

toDataURL

Get data-URL of your drawings! ```javascript designer.toDataURL('image/png', function(dataURL) {
window.open(dataURL);
}); ```

sync

You can manually sync drawings by invoking designer.sync method: ```javascript designer.sync(); ``` Here is a real usecase: ```javascript webrtcDataChannel.onopen = function() {
if(designer.pointsLength > 0) {
// you seems having data to be synced with new user!
designer.sync();
}
}; ```

captureStream

Get MediaStream object and share in realtime using RTCPeerConnection.addStream API. ```html ```

pointsLength

Each shape is considered as a point. This value allows you check number of shapes that are already drawn on the canvas-designer. ```javascript (function looper() {
document.getElementById('number-of-shapes').inenrHTML = designer.pointsLength;
setTimeout(looper, 1000);
})(); ``` Or a real usage: ```javascript websocket.onopen = function() {
if(designer.pointsLength > 0) {
// you seems having data to be synced with existing users!
designer.sync();
}
}; ```

undo

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: ```javascript 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
}) ``` designer.pointsLength shows number of shapes; and designer.undo accepts shape-index as well.

Add New Tools

First Step

Open widget.html and add your new tool-icon HTML. ```html
<canvas id="yourNewToolIcon" width="40" height="40"></canvas> <!-- here is your icon-HTML -->
```

Second Step

Open decorator.js and decorate your new HTML icon. ```javascript 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: ```javascript 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'; ```

Third Step

Open common.js and add selection-states for your new tool-icon (i.e. whether your new tool icon is selected or not): ```javascript 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.

Fourth Step

Create new file in the dev directory. Name this file as yourNewToolIcon-handler.js. This file MUST look like this: ```javascript 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.

Fifth Step

Open events-handler.js and make sure that your above yourNewToolIconHandler object is called for mouse up/down/move events. ```javascript 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.

Sixth Step

Open draw-helper.js. Make sure that your new tool-icon can be drawn on the <canvas> surface. ```javascript 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.

Seventh Step

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.

Eighth Step

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:
  1. forLoop
  1. absoluteNOTShortened
  1. relativeShortened
  1. relativeNOTShortened
Search for p[0] === 'line' and add similar code-blocks for your shape (new-tool-icon) as well.

For more information

  • https://www.webrtc-experiment.com/Canvas-Designer/Help/#contribute
Shortcut Keys
``` 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)
Signaling Server
You need only these two files:
  1. server.js
  1. Signaling-Server.js
You also need to manually install socket.io: ```sh wget https://raw.githubusercontent.com/muaz-khan/RTCMultiConnection/master/server.js wget https://raw.githubusercontent.com/muaz-khan/RTCMultiConnection/master/Signaling-Server.js npm install socket.io --save-dev node server --port=9002 --ssl --sslkey=/home/ssl/ssl.key --sslcert=/home/ssl/ssl.crt ``` For more info:
  • https://github.com/muaz-khan/RTCMultiConnection/tree/master/docs/installation-guide.md
Contributors
  1. Muaz Khan
  1. Oleg Aliullov
Please make pull-request to update this list.
License
Canvas Designer is released under MIT licence . Copyright (c) Muaz Khan.