Skip to content

Commit

Permalink
Added [email protected] Added "Arrow" tool
Browse files Browse the repository at this point in the history
  • Loading branch information
muaz-khan committed May 16, 2016
1 parent 40ccdb8 commit 09f8a17
Show file tree
Hide file tree
Showing 16 changed files with 539 additions and 65 deletions.
1 change: 1 addition & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = function(grunt) {
'dev/text-handler.js',
'dev/arc-handler.js',
'dev/line-handler.js',
'dev/arrow-handler.js',
'dev/rect-handler.js',
'dev/quadratic-handler.js',
'dev/bezier-handler.js',
Expand Down
47 changes: 24 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ The specialty of this drawing-tool is that, it generates Canvas2D code for you;

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!

# [Click to view Gif Presentation](https://cdn.webrtc-experiment.com/images/Canvas-Designer.gif)
### Youtube Videos

* https://www.youtube.com/watch?v=oSSwMlBu8SY

Gif images:

* https://cdn.webrtc-experiment.com/images/Canvas-Designer.gif

<img src="https://i.imgur.com/uDbfy1F.png" />

Expand All @@ -38,15 +44,15 @@ You can use [`designer.setSelected`](https://github.com/muaz-khan/Canvas-Designe
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

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 & features:

1. `arrow` --- to draw arrows
2. Resize all shapes at once (currently you can resize last selected shape only)
1. Resize all shapes at once (currently you can resize last selected shape only)

# Features

Expand Down Expand Up @@ -88,20 +94,20 @@ You can paste any text: English, Arabic, Chinese etc.

`designer.appendTo(document.body);`

E.g. (Please don't forget replacing `1.0.6` with latest version)
E.g. (Please don't forget replacing `1.0.7` with latest version)

```html
<!-- 1st step -->
<script src="https://github.com/muaz-khan/Canvas-Designer/releases/download/1.0.6/canvas-designer-widget.js"></script>
<script src="https://github.com/muaz-khan/Canvas-Designer/releases/download/1.0.7/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://github.com/muaz-khan/Canvas-Designer/releases/download/1.0.6/widget.html'; // you can place this file anywhere
designer.widgetJsURL = 'https://github.com/muaz-khan/Canvas-Designer/releases/download/1.0.6/widget.js'; // you can place this file anywhere
designer.widgetHtmlURL = 'https://github.com/muaz-khan/Canvas-Designer/releases/download/1.0.7/widget.html'; // you can place this file anywhere
designer.widgetJsURL = 'https://github.com/muaz-khan/Canvas-Designer/releases/download/1.0.7/widget.js'; // you can place this file anywhere
</script>

<!-- 3rd i.e. last step -->
Expand Down Expand Up @@ -245,8 +251,18 @@ This method allows you choose between tools that **should be displayed** in the

```javascript
designer.setTools({
line: true,
arrow: true,
pencil: true,
text: true
dragSingle: true,
dragMultiple: true,
eraser: true,
rectangle: true,
arc: true,
bezier: true,
quadratic: true,
text: true,
image: true
});
```

Expand Down Expand Up @@ -376,21 +392,6 @@ ctrl+c (copy last-selected shape)
ctrl+v (paste last-copied shape)
```

# Demos

* http://muaz-khan.github.io/Everything/Canvas/ (A-to-zee all shapes, and animations on this page is created using canvas-designer)
* https://www.webrtc-experiment.com/Canvas-Designer/ (canvas-designer demo allows you draw shapes & get the code; additionally collaborate as well!)
* Try a simple canvas2d animation demo: http://muaz-khan.github.io/Everything/Canvas/Experiments/Simple-HTML5-Canvas-Experiment/
* Try many other canvas2d demos: http://muaz-khan.github.io/Everything/Canvas/Experiments/

All above demos are built using canvas-designer!

Original source-code was shared 2-years back, here: https://github.com/muaz-khan/Everything/tree/gh-pages/Canvas/Tools/Designer

There is a similar "tinny" tool, however it isn't yet supporting collaboration: https://canvature.appspot.com/

And WebRTC-Experiments! https://github.com/muaz-khan/WebRTC-Experiment

# License

[Canvas Designer](https://github.com/muaz-khan/Canvas-Designer) is released under [MIT licence](https://www.webrtc-experiment.com/licence/) . Copyright (c) [Muaz Khan](http://www.MuazKhan.com).
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "canvas-designer",
"preferGlobal": false,
"version": "1.0.6",
"version": "1.0.7",
"author": {
"name": "Muaz Khan",
"email": "[email protected]",
Expand Down
1 change: 1 addition & 0 deletions canvas-designer-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function CanvasDesigner() {

var tools = {
line: true,
arrow: true,
pencil: true,
dragSingle: true,
dragMultiple: true,
Expand Down
40 changes: 40 additions & 0 deletions dev/arrow-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
var arrowHandler = {
ismousedown: false,
prevX: 0,
prevY: 0,
arrowSize: 10,
mousedown: function(e) {
var x = e.pageX - canvas.offsetLeft,
y = e.pageY - canvas.offsetTop;

var t = this;

t.prevX = x;
t.prevY = y;

t.ismousedown = true;
},
mouseup: function(e) {
var x = e.pageX - canvas.offsetLeft,
y = e.pageY - canvas.offsetTop;

var t = this;
if (t.ismousedown) {
points[points.length] = ['arrow', [t.prevX, t.prevY, x, y], drawHelper.getOptions()];

t.ismousedown = false;
}
},
mousemove: function(e) {
var x = e.pageX - canvas.offsetLeft,
y = e.pageY - canvas.offsetTop;

var t = this;

if (t.ismousedown) {
tempContext.clearRect(0, 0, innerWidth, innerHeight);

drawHelper.arrow(tempContext, [t.prevX, t.prevY, x, y]);
}
}
};
110 changes: 94 additions & 16 deletions dev/common.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var is = {
isLine: false,
isArrow: false,
isArc: false,
isDragLastPath: false,
isDragAllPaths: false,
Expand All @@ -14,7 +15,7 @@ var is = {
set: function(shape) {
var cache = this;

cache.isLine = cache.isArc = cache.isDragLastPath = cache.isDragAllPaths = cache.isRectangle = cache.isQuadraticCurve = cache.isBezierCurve = cache.isPencil = cache.isEraser = cache.isText = cache.isImage = false;
cache.isLine = cache.isArrow = cache.isArc = cache.isDragLastPath = cache.isDragAllPaths = cache.isRectangle = cache.isQuadraticCurve = cache.isBezierCurve = cache.isPencil = cache.isEraser = cache.isText = cache.isImage = false;
cache['is' + shape] = true;
}
};
Expand Down Expand Up @@ -96,7 +97,7 @@ var common = {
}

output = output.substr(0, output.length - 2);
textarea.value = 'var points = [' + output + '], length = points.length, point, p, i = 0;\n\n' + this.forLoop;
textarea.value = 'var points = [' + output + '], length = points.length, point, p, i = 0;\n\n' + drawArrow.toString() + '\n\n' + this.forLoop;

this.prevProps = null;
},
Expand Down Expand Up @@ -124,6 +125,10 @@ var common = {
tempArray[i] = [this.strokeOrFill(p[2]) + '\ncontext.fillText(' + point[0] + ', ' + point[1] + ', ' + point[2] + ');'];
}

if (p[0] === 'arrow') {
tempArray[i] = ['drawArrow(' + point[0] + ', ' + point[1] + ', ' + point[2] + ', ' + point[3] + ', \'' + p[2].join('\',\'') + '\');'];
}

if (p[0] === 'arc') {
tempArray[i] = ['context.beginPath(); \n' + 'context.arc(' + toFixed(point[0]) + ',' + toFixed(point[1]) + ',' + toFixed(point[2]) + ',' + toFixed(point[3]) + ', 0,' + point[4] + '); \n' + this.strokeOrFill(p[2])];
}
Expand All @@ -141,7 +146,7 @@ var common = {
}

}
textarea.value = tempArray.join('\n\n') + this.strokeFillText;
textarea.value = tempArray.join('\n\n') + this.strokeFillText + '\n\n' + drawArrow.toString();

this.prevProps = null;
},
Expand Down Expand Up @@ -193,6 +198,15 @@ var common = {
], p[2]);
}

if (p[0] === 'arrow') {
output += this.shortenHelper(p[0], [
getPoint(point[0], x, 'x'),
getPoint(point[1], y, 'y'),
getPoint(point[2], x, 'x'),
getPoint(point[3], y, 'y')
], p[2]);
}

if (p[0] === 'text') {
output += this.shortenHelper(p[0], [
point[0],
Expand Down Expand Up @@ -246,7 +260,7 @@ var common = {
}

output = output.substr(0, output.length - 2);
textarea.value = 'var x = ' + x + ', y = ' + y + ', points = [' + output + '], length = points.length, point, p, i = 0;\n\n' + this.forLoop;
textarea.value = 'var x = ' + x + ', y = ' + y + ', points = [' + output + '], length = points.length, point, p, i = 0;\n\n' + drawArrow.toString() + '\n\n' + this.forLoop;

this.prevProps = null;
},
Expand Down Expand Up @@ -296,6 +310,10 @@ var common = {
+ this.strokeOrFill(p[2]);
}

if (p[0] === 'arrow') {
output += 'drawArrow(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ', ' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ', \'' + p[2].join('\',\'') + '\');\n';
}

if (p[0] === 'text') {
output += this.strokeOrFill(p[2]) + '\n' + 'context.fillText(' + point[0] + ', ' + getPoint(point[1], x, 'x') + ', ' + getPoint(point[2], y, 'y') + ');';
}
Expand All @@ -318,60 +336,64 @@ var common = {

if (i !== length - 1) output += '\n\n';
}
textarea.value = output + this.strokeFillText;
textarea.value = output + this.strokeFillText + '\n\n' + drawArrow.toString();

this.prevProps = null;
},
forLoop: 'for(i; i < length; i++) {\n' + ' p = points[i];\n' + ' point = p[1];\n' + ' context.beginPath();\n\n'

// globals
+ ' if(p[2]) { \n' + ' context.lineWidth = p[2][0];\n' + ' context.strokeStyle = p[2][1];\n' + ' context.fillStyle = p[2][2];\n'
+ ' if(p[2]) { \n' + '\tcontext.lineWidth = p[2][0];\n' + '\tcontext.strokeStyle = p[2][1];\n' + '\tcontext.fillStyle = p[2][2];\n'

+ ' context.globalAlpha = p[2][3];\n' + ' context.globalCompositeOperation = p[2][4];\n' + ' context.lineCap = p[2][5];\n' + ' context.lineJoin = p[2][6];\n' + ' context.font = p[2][7];\n' + ' }\n\n'
+ '\tcontext.globalAlpha = p[2][3];\n' + '\tcontext.globalCompositeOperation = p[2][4];\n' + '\tcontext.lineCap = p[2][5];\n' + '\tcontext.lineJoin = p[2][6];\n' + '\tcontext.font = p[2][7];\n' + ' }\n\n'

// line

+ ' if(p[0] === "line") { \n' + ' context.moveTo(point[0], point[1]);\n' + ' context.lineTo(point[2], point[3]);\n' + ' }\n\n'
+ ' if(p[0] === "line") { \n' + '\tcontext.moveTo(point[0], point[1]);\n' + '\tcontext.lineTo(point[2], point[3]);\n' + ' }\n\n'

// arrow

+ ' if(p[0] === "arrow") { \n' + '\tdrawArrow(point[0], point[1], point[2], point[3], p[2]);\n' + ' }\n\n'

// pencil

+ ' if(p[0] === "pencil") { \n' + ' context.moveTo(point[0], point[1]);\n' + ' context.lineTo(point[2], point[3]);\n' + ' }\n\n'
+ ' if(p[0] === "pencil") { \n' + '\tcontext.moveTo(point[0], point[1]);\n' + '\tcontext.lineTo(point[2], point[3]);\n' + ' }\n\n'

// text

+ ' if(p[0] === "text") { \n' + ' context.fillText(point[0], point[1], point[2]);\n' + ' }\n\n'
+ ' if(p[0] === "text") { \n' + '\tcontext.fillText(point[0], point[1], point[2]);\n' + ' }\n\n'

// eraser

+ ' if(p[0] === "eraser") { \n' + ' context.moveTo(point[0], point[1]);\n' + ' context.lineTo(point[2], point[3]);\n' + ' }\n\n'
+ ' if(p[0] === "eraser") { \n' + '\tcontext.moveTo(point[0], point[1]);\n' + '\tcontext.lineTo(point[2], point[3]);\n' + ' }\n\n'

// arc

+ ' if(p[0] === "arc") context.arc(point[0], point[1], point[2], point[3], 0, point[4]); \n\n'

// rect

+ ' if(p[0] === "rect") {\n' + ' context.strokeRect(point[0], point[1], point[2], point[3]);\n' + ' context.fillRect(point[0], point[1], point[2], point[3]);\n'
+ ' if(p[0] === "rect") {\n' + '\tcontext.strokeRect(point[0], point[1], point[2], point[3]);\n' + '\tcontext.fillRect(point[0], point[1], point[2], point[3]);\n'

+ ' }\n\n'

// quadratic

+ ' if(p[0] === "quadratic") {\n' + ' context.moveTo(point[0], point[1]);\n' + ' context.quadraticCurveTo(point[2], point[3], point[4], point[5]);\n' + ' }\n\n'
+ ' if(p[0] === "quadratic") {\n' + '\tcontext.moveTo(point[0], point[1]);\n' + '\tcontext.quadraticCurveTo(point[2], point[3], point[4], point[5]);\n' + ' }\n\n'

// bezier

+ ' if(p[0] === "bezier") {\n' + ' context.moveTo(point[0], point[1]);\n' + ' context.bezierCurveTo(point[2], point[3], point[4], point[5], point[6], point[7]);\n' + ' }\n\n'
+ ' if(p[0] === "bezier") {\n' + '\tcontext.moveTo(point[0], point[1]);\n' + '\tcontext.bezierCurveTo(point[2], point[3], point[4], point[5], point[6], point[7]);\n' + ' }\n\n'

// end-fill

+ ' context.stroke();\n' + ' context.fill();\n'

+ '}',

strokeFillText: '\n\nfunction strokeOrFill(lineWidth, strokeStyle, fillStyle, globalAlpha, globalCompositeOperation, lineCap, lineJoin, font) { \n' + ' if(lineWidth) { \n' + ' context.globalAlpha = globalAlpha;\n' + ' context.globalCompositeOperation = globalCompositeOperation;\n' + ' context.lineCap = lineCap;\n' + ' context.lineJoin = lineJoin;\n'
strokeFillText: '\n\nfunction strokeOrFill(lineWidth, strokeStyle, fillStyle, globalAlpha, globalCompositeOperation, lineCap, lineJoin, font) { \n' + ' if(lineWidth) { \n' + '\tcontext.globalAlpha = globalAlpha;\n' + '\tcontext.globalCompositeOperation = globalCompositeOperation;\n' + '\tcontext.lineCap = lineCap;\n' + '\tcontext.lineJoin = lineJoin;\n'

+ ' context.lineWidth = lineWidth;\n' + ' context.strokeStyle = strokeStyle;\n' + ' context.fillStyle = fillStyle;\n' + ' context.font = font;\n' + ' } \n\n'
+ '\tcontext.lineWidth = lineWidth;\n' + '\tcontext.strokeStyle = strokeStyle;\n' + '\tcontext.fillStyle = fillStyle;\n' + '\tcontext.font = font;\n' + ' } \n\n'

+ ' context.stroke();\n' + ' context.fill();\n'

Expand All @@ -398,6 +420,62 @@ var common = {
}
};

function drawArrow(mx, my, lx, ly, options) {
function getOptions(opt) {
opt = opt || {};

return [
opt.lineWidth || 2,
opt.strokeStyle || '#6c96c8',
opt.fillStyle || 'transparent',
opt.globalAlpha || 1,
opt.globalCompositeOperation || 'source-over',
opt.lineCap || 'round',
opt.lineJoin || 'round',
opt.font || '15px "Arial"'
];
}

function handleOptions(opt, isNoFillStroke) {
opt = opt || getOptions();

context.globalAlpha = opt[3];
context.globalCompositeOperation = opt[4];

context.lineCap = opt[5];
context.lineJoin = opt[6];
context.lineWidth = opt[0];

context.strokeStyle = opt[1];
context.fillStyle = opt[2];

context.font = opt[7];

if (!isNoFillStroke) {
context.stroke();
context.fill();
}
}

var arrowSize = 10;
var angle = Math.atan2(ly - my, lx - mx);

context.beginPath();
context.moveTo(mx, my);
context.lineTo(lx, ly);

handleOptions();

context.beginPath();
context.moveTo(lx, ly);
context.lineTo(lx - arrowSize * Math.cos(angle - Math.PI / 7), ly - arrowSize * Math.sin(angle - Math.PI / 7));
context.lineTo(lx - arrowSize * Math.cos(angle + Math.PI / 7), ly - arrowSize * Math.sin(angle + Math.PI / 7));
context.lineTo(lx, ly);
context.lineTo(lx - arrowSize * Math.cos(angle - Math.PI / 7), ly - arrowSize * Math.sin(angle - Math.PI / 7));

handleOptions();
}

function endLastPath() {
var cache = is;

Expand Down
Loading

0 comments on commit 09f8a17

Please sign in to comment.