Canvas-Designer

by muaz-khan

muaz-khan / Canvas-Designer

Collaborative, extendable, JavaScript Canvas2D drawing tool, supports dozens of builtin tools, as we...

243 Stars 134 Forks Last release: almost 2 years ago (1.3.0) MIT License 59 Commits 13 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Canvas Designer / API Referencee

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=pvAj5l_v3cM

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://www.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
  2. pencil
    --- to write/draw shapes
  3. dragSingle
    --- to drag/ove and especially resize last selected shape
  4. dragMultiple
    --- to drag/move all shapes
  5. eraser
    --- to erase/clear specific portion of shapes
  6. rectangle
    --- to draw rectangles
  7. arc
    --- to draw circles
  8. bezier
    --- to draw bezier curves
  9. quadratic
    --- to draw quadratic curves
  10. text
    --- to write texts on single or multiple lines, select font families/sizes and more
  11. image
    --- add external images
  12. arrow
    --- draw arrow lines
  13. marker
    --- draw markers
  14. lineWidth
    --- set line width
  15. colorsPicker
    --- background and foreground colors picker
  16. extraOptions
    --- extra options eg. lineCap, lineJoin, globalAlpha, globalCompositeOperation etc.
  17. pdf
    --- to import PDF
  18. code
    --- to enable/disable code view
  19. 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
  2. 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)
  2. Drag/resize/adjust all the shapes in any possible direction
  3. 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)
  2. 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

 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
  2. 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.
  2. Set
    designer.widgetHtmlURL
    and
    designer.widgetJsURL
    in your HTML file.
  3. Use this command to append widget in your HTML page:

var designer = new CanvasDesigner();

designer.appendTo(document.body);





Complete Usage

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); });

Use Socket.io

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.
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
.

widgetJsURL

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
.

syncData

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 });

clearCanvas

Remove and clear all drawings from the canvas:

designer.clearCanvas();

renderStream

Call this method internally to fix video rendering issues.

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.

designer.addSyncListener(function(data) {
    designer.send(JSON.stringify(data));
});

setSelected

This method allows you select specific tools.

designer.setSelected('rectangle');

setTools

This method allows you choose between tools that should be displayed in the tools-panel.

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:

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
.

appendTo

CanvasDesigner is a widget; that widget should be appended to a DOM object. This method allows you pass

 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

destroy

If you want to remove the widget from your HTMLDOMElement.

designer.destroy();

iframe

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';

toDataURL

Get data-URL of your drawings!

designer.toDataURL('image/png', function(dataURL) {
    window.open(dataURL);
});

sync

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();
    }
};

captureStream

Get

MediaStream
object and share in realtime using
RTCPeerConnection.addStream
API.

pointsLength

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();
    }
};

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:
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.

Add New Tools

First Step

Open

widget.html
and add your new tool-icon HTML.

Second Step

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';

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):

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:

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.
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

 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.

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

 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
  2. absoluteNOTShortened
  3. relativeShortened
  4. 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

  • https://github.com/muaz-khan/RTCMultiConnection-Server

Contributors

  1. Muaz Khan
  2. Oleg Aliullov

Please make pull-request to update this list.

License

Canvas Designer is released under MIT license . Copyright (c) Muaz Khan.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.