@vikasietum_tecknology/record-rtc
Version:
record-rtc is a library based on recordrtc library. In this forked version of the original library we have optimized the memory management. The video recording is stored in IndexDB in chunks.
1,367 lines (1,084 loc) • 126 kB
JavaScript
// Last time updated: 2017-07-03 1:56:26 PM UTC
// _______________
// Canvas-Designer
// https://github.com/muaz-khan/Canvas-Designer
'use strict';
(function() {
var is = {
isLine: false,
isArrow: false,
isArc: false,
isDragLastPath: false,
isDragAllPaths: false,
isRectangle: false,
isQuadraticCurve: false,
isBezierCurve: false,
isPencil: false,
isMarker: true,
isEraser: false,
isText: false,
isImage: false,
set: function(shape) {
var cache = this;
cache.isLine = cache.isArrow = cache.isArc = cache.isDragLastPath = cache.isDragAllPaths = cache.isRectangle = cache.isQuadraticCurve = cache.isBezierCurve = cache.isPencil = cache.isMarker = cache.isEraser = cache.isText = cache.isImage = false;
cache['is' + shape] = true;
}
};
function addEvent(element, eventType, callback) {
if (eventType.split(' ').length > 1) {
var events = eventType.split(' ');
for (var i = 0; i < events.length; i++) {
addEvent(element, events[i], callback);
}
return;
}
if (element.addEventListener) {
element.addEventListener(eventType, callback, !1);
return true;
} else if (element.attachEvent) {
return element.attachEvent('on' + eventType, callback);
} else {
element['on' + eventType] = callback;
}
return this;
}
function find(selector) {
return document.getElementById(selector);
}
var points = [],
textarea = find('code-text'),
lineWidth = 2,
strokeStyle = '#6c96c8',
fillStyle = 'white',
globalAlpha = 1,
globalCompositeOperation = 'source-over',
lineCap = 'round',
font = '15px "Arial"',
lineJoin = 'round';
function getContext(id) {
var canv = find(id),
ctx = canv.getContext('2d');
canv.setAttribute('width', innerWidth);
canv.setAttribute('height', innerHeight);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeStyle;
ctx.fillStyle = fillStyle;
ctx.font = font;
return ctx;
}
var context = getContext('main-canvas'),
tempContext = getContext('temp-canvas');
window.canvasElementToBeRecorded = context.canvas; // either use "tempContext.canvas" or "context.canvas"
context._clearRect = context.clearRect;
context.clearRect = function(x, y, width, height) {
context._clearRect(0, 0, context.canvas.width, context.canvas.height);
fillStyle = 'white';
context.fillRect(0, 0, context.canvas.width, context.canvas.height); // fill white background
};
var common = {
updateTextArea: function() {
var c = common,
toFixed = c.toFixed,
getPoint = c.getPoint,
isAbsolutePoints = find('is-absolute-points').checked,
isShortenCode = find('is-shorten-code').checked;
if (isAbsolutePoints && isShortenCode) c.absoluteShortened();
if (isAbsolutePoints && !isShortenCode) c.absoluteNOTShortened(toFixed);
if (!isAbsolutePoints && isShortenCode) c.relativeShortened(toFixed, getPoint);
if (!isAbsolutePoints && !isShortenCode) c.relativeNOTShortened(toFixed, getPoint);
},
toFixed: function(input) {
return Number(input).toFixed(1);
},
getPoint: function(pointToCompare, compareWith, prefix) {
if (pointToCompare > compareWith) pointToCompare = prefix + ' + ' + (pointToCompare - compareWith);
else if (pointToCompare < compareWith) pointToCompare = prefix + ' - ' + (compareWith - pointToCompare);
else pointToCompare = prefix;
return pointToCompare;
},
absoluteShortened: function() {
var output = '',
length = points.length,
i = 0,
point;
for (i; i < length; i++) {
point = points[i];
output += this.shortenHelper(point[0], point[1], point[2]);
}
output = output.substr(0, output.length - 2);
textarea.value = 'var points = [' + output + '], length = points.length, point, p, i = 0;\n\n' + drawArrow.toString() + '\n\n' + this.forLoop;
this.prevProps = null;
},
absoluteNOTShortened: function(toFixed) {
var tempArray = [],
i, point, p;
for (i = 0; i < points.length; i++) {
p = points[i];
point = p[1];
if (p[0] === 'pencil') {
tempArray[i] = ['context.beginPath();\n' + 'context.moveTo(' + point[0] + ', ' + point[1] + ');\n' + 'context.lineTo(' + point[2] + ', ' + point[3] + ');\n' + this.strokeOrFill(p[2])];
}
if (p[0] === 'marker') {
tempArray[i] = ['context.beginPath();\n' + 'context.moveTo(' + point[0] + ', ' + point[1] + ');\n' + 'context.lineTo(' + point[2] + ', ' + point[3] + ');\n' + this.strokeOrFill(p[2])];
}
if (p[0] === 'eraser') {
tempArray[i] = ['context.beginPath();\n' + 'context.moveTo(' + point[0] + ', ' + point[1] + ');\n' + 'context.lineTo(' + point[2] + ', ' + point[3] + ');\n' + this.strokeOrFill(p[2])];
}
if (p[0] === 'line') {
tempArray[i] = ['context.beginPath();\n' + 'context.moveTo(' + point[0] + ', ' + point[1] + ');\n' + 'context.lineTo(' + point[2] + ', ' + point[3] + ');\n' + this.strokeOrFill(p[2])];
}
if (p[0] === 'text') {
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])];
}
if (p[0] === 'rect') {
tempArray[i] = [this.strokeOrFill(p[2]) + '\n' + 'context.strokeRect(' + point[0] + ', ' + point[1] + ',' + point[2] + ',' + point[3] + ');\n' + 'context.fillRect(' + point[0] + ', ' + point[1] + ',' + point[2] + ',' + point[3] + ');'];
}
if (p[0] === 'quadratic') {
tempArray[i] = ['context.beginPath();\n' + 'context.moveTo(' + point[0] + ', ' + point[1] + ');\n' + 'context.quadraticCurveTo(' + point[2] + ', ' + point[3] + ', ' + point[4] + ', ' + point[5] + ');\n' + this.strokeOrFill(p[2])];
}
if (p[0] === 'bezier') {
tempArray[i] = ['context.beginPath();\n' + 'context.moveTo(' + point[0] + ', ' + point[1] + ');\n' + 'context.bezierCurveTo(' + point[2] + ', ' + point[3] + ', ' + point[4] + ', ' + point[5] + ', ' + point[6] + ', ' + point[7] + ');\n' + this.strokeOrFill(p[2])];
}
}
textarea.value = tempArray.join('\n\n') + this.strokeFillText + '\n\n' + drawArrow.toString();
this.prevProps = null;
},
relativeShortened: function(toFixed, getPoint) {
var i = 0,
point, p, length = points.length,
output = '',
x = 0,
y = 0;
for (i; i < length; i++) {
p = points[i];
point = p[1];
if (i === 0) {
x = point[0];
y = point[1];
}
if (p[0] === 'text') {
x = point[1];
y = point[2];
}
if (p[0] === 'pencil') {
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] === 'marker') {
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] === 'eraser') {
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] === 'line') {
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] === '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],
getPoint(point[1], x, 'x'),
getPoint(point[2], y, 'y')
], p[2]);
}
if (p[0] === 'arc') {
output += this.shortenHelper(p[0], [
getPoint(point[0], x, 'x'),
getPoint(point[1], y, 'y'),
point[2],
point[3],
point[4]
], p[2]);
}
if (p[0] === 'rect') {
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] === 'quadratic') {
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'),
getPoint(point[4], x, 'x'),
getPoint(point[5], y, 'y')
], p[2]);
}
if (p[0] === 'bezier') {
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'),
getPoint(point[4], x, 'x'),
getPoint(point[5], y, 'y'),
getPoint(point[6], x, 'x'),
getPoint(point[7], y, 'y')
], p[2]);
}
}
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' + drawArrow.toString() + '\n\n' + this.forLoop;
this.prevProps = null;
},
relativeNOTShortened: function(toFixed, getPoint) {
var i, point, p, length = points.length,
output = '',
x = 0,
y = 0;
for (i = 0; i < length; i++) {
p = points[i];
point = p[1];
if (i === 0) {
x = point[0];
y = point[1];
if (p[0] === 'text') {
x = point[1];
y = point[2];
}
output = 'var x = ' + x + ', y = ' + y + ';\n\n';
}
if (p[0] === 'arc') {
output += 'context.beginPath();\n' + 'context.arc(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ', ' + point[2] + ', ' + point[3] + ', 0, ' + point[4] + ');\n'
+
this.strokeOrFill(p[2]);
}
if (p[0] === 'pencil') {
output += 'context.beginPath();\n' + 'context.moveTo(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ');\n' + 'context.lineTo(' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ');\n'
+
this.strokeOrFill(p[2]);
}
if (p[0] === 'marker') {
output += 'context.beginPath();\n' + 'context.moveTo(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ');\n' + 'context.lineTo(' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ');\n'
+
this.strokeOrFill(p[2]);
}
if (p[0] === 'eraser') {
output += 'context.beginPath();\n' + 'context.moveTo(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ');\n' + 'context.lineTo(' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ');\n'
+
this.strokeOrFill(p[2]);
}
if (p[0] === 'line') {
output += 'context.beginPath();\n' + 'context.moveTo(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ');\n' + 'context.lineTo(' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ');\n'
+
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') + ');';
}
if (p[0] === 'rect') {
output += this.strokeOrFill(p[2]) + '\n' + 'context.strokeRect(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ', ' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ');\n' + 'context.fillRect(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ', ' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ');';
}
if (p[0] === 'quadratic') {
output += 'context.beginPath();\n' + 'context.moveTo(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ');\n' + 'context.quadraticCurveTo(' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ', ' + getPoint(point[4], x, 'x') + ', ' + getPoint(point[5], y, 'y') + ');\n'
+
this.strokeOrFill(p[2]);
}
if (p[0] === 'bezier') {
output += 'context.beginPath();\n' + 'context.moveTo(' + getPoint(point[0], x, 'x') + ', ' + getPoint(point[1], y, 'y') + ');\n' + 'context.bezierCurveTo(' + getPoint(point[2], x, 'x') + ', ' + getPoint(point[3], y, 'y') + ', ' + getPoint(point[4], x, 'x') + ', ' + getPoint(point[5], y, 'y') + ', ' + getPoint(point[6], x, 'x') + ', ' + getPoint(point[7], y, 'y') + ');\n'
+
this.strokeOrFill(p[2]);
}
if (i !== length - 1) output += '\n\n';
}
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' + '\tcontext.lineWidth = p[2][0];\n' + '\tcontext.strokeStyle = p[2][1];\n' + '\tcontext.fillStyle = p[2][2];\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' + '\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' + '\tcontext.moveTo(point[0], point[1]);\n' + '\tcontext.lineTo(point[2], point[3]);\n' + ' }\n\n'
// marker
+
' if(p[0] === "marker") { \n' + '\tcontext.moveTo(point[0], point[1]);\n' + '\tcontext.lineTo(point[2], point[3]);\n' + ' }\n\n'
// text
+
' if(p[0] === "text") { \n' + '\tcontext.fillText(point[0], point[1], point[2]);\n' + ' }\n\n'
// eraser
+
' 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' + '\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' + '\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' + '\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' + '\tcontext.globalAlpha = globalAlpha;\n' + '\tcontext.globalCompositeOperation = globalCompositeOperation;\n' + '\tcontext.lineCap = lineCap;\n' + '\tcontext.lineJoin = lineJoin;\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'
+
'}',
strokeOrFill: function(p) {
if (!this.prevProps || this.prevProps !== p.join(',')) {
this.prevProps = p.join(',');
return 'strokeOrFill(\'' + p.join('\', \'') + '\');';
}
return 'strokeOrFill();';
},
prevProps: null,
shortenHelper: function(name, p1, p2) {
var result = '[\'' + name + '\', [' + p1.join(', ') + ']';
if (!this.prevProps || this.prevProps !== p2.join(',')) {
this.prevProps = p2.join(',');
result += ', [\'' + p2.join('\', \'') + '\']';
}
return result + '], ';
}
};
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;
if (cache.isArc) arcHandler.end();
else if (cache.isQuadraticCurve) quadraticHandler.end();
else if (cache.isBezierCurve) bezierHandler.end();
drawHelper.redraw();
if (textHandler.text && textHandler.text.length) {
textHandler.appendPoints();
textHandler.onShapeUnSelected();
}
textHandler.showOrHideTextTools('hide');
}
var copiedStuff = [],
isControlKeyPressed;
function copy() {
endLastPath();
dragHelper.global.startingIndex = 0;
if (find('copy-last').checked) {
copiedStuff = points[points.length - 1];
setSelection(find('drag-last-path'), 'DragLastPath');
} else {
copiedStuff = points;
setSelection(find('drag-all-paths'), 'DragAllPaths');
}
}
function paste() {
endLastPath();
dragHelper.global.startingIndex = 0;
if (find('copy-last').checked) {
points[points.length] = copiedStuff;
dragHelper.global = {
prevX: 0,
prevY: 0,
startingIndex: points.length - 1
};
dragHelper.dragAllPaths(0, 0);
setSelection(find('drag-last-path'), 'DragLastPath');
} else {
dragHelper.global.startingIndex = points.length;
points = points.concat(copiedStuff);
setSelection(find('drag-all-paths'), 'DragAllPaths');
}
}
// marker + pencil
function hexToR(h) {
return parseInt((cutHex(h)).substring(0, 2), 16)
}
function hexToG(h) {
return parseInt((cutHex(h)).substring(2, 4), 16)
}
function hexToB(h) {
return parseInt((cutHex(h)).substring(4, 6), 16)
}
function cutHex(h) {
return (h.charAt(0) == "#") ? h.substring(1, 7) : h
}
function clone(obj) {
if (obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj)
return obj;
if (obj instanceof Date)
var temp = new obj.constructor(); //or new Date(obj);
else
var temp = obj.constructor();
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = clone(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
function hexToRGB(h) {
return [
hexToR(h),
hexToG(h),
hexToB(h)
]
}
var drawHelper = {
redraw: function() {
tempContext.clearRect(0, 0, innerWidth, innerHeight);
context.clearRect(0, 0, innerWidth, innerHeight);
var i, point, length = points.length;
for (i = 0; i < length; i++) {
point = points[i];
if (point && point.length && this[point[0]]) {
this[point[0]](context, point[1], point[2]);
}
// else warn
}
},
getOptions: function(opt) {
opt = opt || {};
return [
opt.lineWidth || lineWidth,
opt.strokeStyle || strokeStyle,
opt.fillStyle || fillStyle,
opt.globalAlpha || globalAlpha,
opt.globalCompositeOperation || globalCompositeOperation,
opt.lineCap || lineCap,
opt.lineJoin || lineJoin,
opt.font || font
];
},
handleOptions: function(context, opt, isNoFillStroke) {
opt = opt || this.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();
}
},
line: function(context, point, options) {
context.beginPath();
context.moveTo(point[0], point[1]);
context.lineTo(point[2], point[3]);
this.handleOptions(context, options);
},
marker: function(context, point, options) {
context.beginPath();
context.moveTo(point[0], point[1]);
context.lineTo(point[2], point[3]);
this.handleOptions(context, options);
},
arrow: function(context, point, options) {
var mx = point[0];
var my = point[1];
var lx = point[2];
var ly = point[3];
var arrowSize = arrowHandler.arrowSize;
if (arrowSize == 10) {
arrowSize = (options ? options[0] : lineWidth) * 5;
}
var angle = Math.atan2(ly - my, lx - mx);
context.beginPath();
context.moveTo(mx, my);
context.lineTo(lx, ly);
this.handleOptions(context, options);
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));
this.handleOptions(context, options);
},
text: function(context, point, options) {
this.handleOptions(context, options);
context.fillStyle = textHandler.getFillColor(options[2]);
context.fillText(point[0].substr(1, point[0].length - 2), point[1], point[2]);
},
arc: function(context, point, options) {
context.beginPath();
context.arc(point[0], point[1], point[2], point[3], 0, point[4]);
this.handleOptions(context, options);
},
rect: function(context, point, options) {
this.handleOptions(context, options, true);
context.strokeRect(point[0], point[1], point[2], point[3]);
context.fillRect(point[0], point[1], point[2], point[3]);
},
image: function(context, point, options) {
this.handleOptions(context, options, true);
var image = imageHandler.images[point[5]];
if (!image) {
var image = new Image();
image.onload = function() {
var index = imageHandler.images.length;
imageHandler.lastImageURL = image.src;
imageHandler.lastImageIndex = index;
imageHandler.images.push(image);
context.drawImage(image, point[1], point[2], point[3], point[4]);
};
image.src = point[0];
return;
}
context.drawImage(image, point[1], point[2], point[3], point[4]);
},
quadratic: function(context, point, options) {
context.beginPath();
context.moveTo(point[0], point[1]);
context.quadraticCurveTo(point[2], point[3], point[4], point[5]);
this.handleOptions(context, options);
},
bezier: function(context, point, options) {
context.beginPath();
context.moveTo(point[0], point[1]);
context.bezierCurveTo(point[2], point[3], point[4], point[5], point[6], point[7]);
this.handleOptions(context, options);
}
};
var dragHelper = {
global: {
prevX: 0,
prevY: 0,
ismousedown: false,
pointsToMove: 'all',
startingIndex: 0
},
mousedown: function(e) {
if (isControlKeyPressed) {
copy();
paste();
isControlKeyPressed = false;
}
var dHelper = dragHelper,
g = dHelper.global;
var x = e.pageX - canvas.offsetLeft,
y = e.pageY - canvas.offsetTop;
g.prevX = x;
g.prevY = y;
g.pointsToMove = 'all';
if (points.length) {
var p = points[points.length - 1],
point = p[1];
if (p[0] === 'line') {
if (dHelper.isPointInPath(x, y, point[0], point[1])) {
g.pointsToMove = 'head';
}
if (dHelper.isPointInPath(x, y, point[2], point[3])) {
g.pointsToMove = 'tail';
}
}
if (p[0] === 'arrow') {
if (dHelper.isPointInPath(x, y, point[0], point[1])) {
g.pointsToMove = 'head';
}
if (dHelper.isPointInPath(x, y, point[2], point[3])) {
g.pointsToMove = 'tail';
}
}
if (p[0] === 'rect') {
if (dHelper.isPointInPath(x, y, point[0], point[1])) {
g.pointsToMove = 'stretch-first';
}
if (dHelper.isPointInPath(x, y, point[0] + point[2], point[1])) {
g.pointsToMove = 'stretch-second';
}
if (dHelper.isPointInPath(x, y, point[0], point[1] + point[3])) {
g.pointsToMove = 'stretch-third';
}
if (dHelper.isPointInPath(x, y, point[0] + point[2], point[1] + point[3])) {
g.pointsToMove = 'stretch-last';
}
}
if (p[0] === 'image') {
if (dHelper.isPointInPath(x, y, point[1], point[2])) {
g.pointsToMove = 'stretch-first';
}
if (dHelper.isPointInPath(x, y, point[1] + point[3], point[2])) {
g.pointsToMove = 'stretch-second';
}
if (dHelper.isPointInPath(x, y, point[1], point[2] + point[4])) {
g.pointsToMove = 'stretch-third';
}
if (dHelper.isPointInPath(x, y, point[1] + point[3], point[2] + point[4])) {
g.pointsToMove = 'stretch-last';
}
}
if (p[0] === 'quadratic') {
if (dHelper.isPointInPath(x, y, point[0], point[1])) {
g.pointsToMove = 'starting-points';
}
if (dHelper.isPointInPath(x, y, point[2], point[3])) {
g.pointsToMove = 'control-points';
}
if (dHelper.isPointInPath(x, y, point[4], point[5])) {
g.pointsToMove = 'ending-points';
}
}
if (p[0] === 'bezier') {
if (dHelper.isPointInPath(x, y, point[0], point[1])) {
g.pointsToMove = 'starting-points';
}
if (dHelper.isPointInPath(x, y, point[2], point[3])) {
g.pointsToMove = '1st-control-points';
}
if (dHelper.isPointInPath(x, y, point[4], point[5])) {
g.pointsToMove = '2nd-control-points';
}
if (dHelper.isPointInPath(x, y, point[6], point[7])) {
g.pointsToMove = 'ending-points';
}
}
}
g.ismousedown = true;
},
mouseup: function() {
var g = this.global;
if (is.isDragLastPath) {
tempContext.clearRect(0, 0, innerWidth, innerHeight);
context.clearRect(0, 0, innerWidth, innerHeight);
this.end();
}
g.ismousedown = false;
},
mousemove: function(e) {
var x = e.pageX - canvas.offsetLeft,
y = e.pageY - canvas.offsetTop,
g = this.global;
drawHelper.redraw();
if (g.ismousedown) {
this.dragShape(x, y);
}
if (is.isDragLastPath) this.init();
},
init: function() {
if (!points.length) return;
var p = points[points.length - 1],
point = p[1],
g = this.global;
if (g.ismousedown) tempContext.fillStyle = 'rgba(255,85 ,154,.9)';
else tempContext.fillStyle = 'rgba(255,85 ,154,.4)';
if (p[0] === 'quadratic') {
tempContext.beginPath();
tempContext.arc(point[0], point[1], 10, Math.PI * 2, 0, !1);
tempContext.arc(point[2], point[3], 10, Math.PI * 2, 0, !1);
tempContext.arc(point[4], point[5], 10, Math.PI * 2, 0, !1);
tempContext.fill();
}
if (p[0] === 'bezier') {
tempContext.beginPath();
tempContext.arc(point[0], point[1], 10, Math.PI * 2, 0, !1);
tempContext.arc(point[2], point[3], 10, Math.PI * 2, 0, !1);
tempContext.arc(point[4], point[5], 10, Math.PI * 2, 0, !1);
tempContext.arc(point[6], point[7], 10, Math.PI * 2, 0, !1);
tempContext.fill();
}
if (p[0] === 'line') {
tempContext.beginPath();
tempContext.arc(point[0], point[1], 10, Math.PI * 2, 0, !1);
tempContext.arc(point[2], point[3], 10, Math.PI * 2, 0, !1);
tempContext.fill();
}
if (p[0] === 'arrow') {
tempContext.beginPath();
tempContext.arc(point[0], point[1], 10, Math.PI * 2, 0, !1);
tempContext.arc(point[2], point[3], 10, Math.PI * 2, 0, !1);
tempContext.fill();
}
if (p[0] === 'text') {
tempContext.font = "15px Verdana";
tempContext.fillText(point[0], point[1], point[2]);
}
if (p[0] === 'rect') {
tempContext.beginPath();
tempContext.arc(point[0], point[1], 10, Math.PI * 2, 0, !1);
tempContext.fill();
tempContext.beginPath();
tempContext.arc(point[0] + point[2], point[1], 10, Math.PI * 2, 0, !1);
tempContext.fill();
tempContext.beginPath();
tempContext.arc(point[0], point[1] + point[3], 10, Math.PI * 2, 0, !1);
tempContext.fill();
tempContext.beginPath();
tempContext.arc(point[0] + point[2], point[1] + point[3], 10, Math.PI * 2, 0, !1);
tempContext.fill();
}
if (p[0] === 'image') {
tempContext.beginPath();
tempContext.arc(point[1], point[2], 10, Math.PI * 2, 0, !1);
tempContext.fill();
tempContext.beginPath();
tempContext.arc(point[1] + point[3], point[2], 10, Math.PI * 2, 0, !1);
tempContext.fill();
tempContext.beginPath();
tempContext.arc(point[1], point[2] + point[4], 10, Math.PI * 2, 0, !1);
tempContext.fill();
tempContext.beginPath();
tempContext.arc(point[1] + point[3], point[2] + point[4], 10, Math.PI * 2, 0, !1);
tempContext.fill();
}
},
isPointInPath: function(x, y, first, second) {
return x > first - 10 && x < first + 10 && y > second - 10 && y < second + 10;
},
getPoint: function(point, prev, otherPoint) {
if (point > prev) {
point = otherPoint + (point - prev);
} else {
point = otherPoint - (prev - point);
}
return point;
},
getXYWidthHeight: function(x, y, prevX, prevY, oldPoints) {
if (oldPoints.pointsToMove == 'stretch-first') {
if (x > prevX) {
oldPoints.x = oldPoints.x + (x - prevX);
oldPoints.width = oldPoints.width - (x - prevX);
} else {
oldPoints.x = oldPoints.x - (prevX - x);
oldPoints.width = oldPoints.width + (prevX - x);
}
if (y > prevY) {
oldPoints.y = oldPoints.y + (y - prevY);
oldPoints.height = oldPoints.height - (y - prevY);
} else {
oldPoints.y = oldPoints.y - (prevY - y);
oldPoints.height = oldPoints.height + (prevY - y);
}
}
if (oldPoints.pointsToMove == 'stretch-second') {
if (x > prevX) {
oldPoints.width = oldPoints.width + (x - prevX);
} else {
oldPoints.width = oldPoints.width - (prevX - x);
}
if (y < prevY) {
oldPoints.y = oldPoints.y + (y - prevY);
oldPoints.height = oldPoints.height - (y - prevY);
} else {
oldPoints.y = oldPoints.y - (prevY - y);
oldPoints.height = oldPoints.height + (prevY - y);
}
}
if (oldPoints.pointsToMove == 'stretch-third') {
if (x > prevX) {
oldPoints.x = oldPoints.x + (x - prevX);
oldPoints.width = oldPoints.width - (x - prevX);
} else {
oldPoints.x = oldPoints.x - (prevX - x);
oldPoints.width = oldPoints.width + (prevX - x);
}
if (y < prevY) {
oldPoints.height = oldPoints.height + (y - prevY);
} else {
oldPoints.height = oldPoints.height - (prevY - y);
}
}
return oldPoints;
},
dragShape: function(x, y) {
if (!this.global.ismousedown) return;
tempContext.clearRect(0, 0, innerWidth, innerHeight);
if (is.isDragLastPath) {
this.dragLastPath(x, y);
}
if (is.isDragAllPaths) {
this.dragAllPaths(x, y);
}
var g = this.global;
g.prevX = x;
g.prevY = y;
},
end: function() {
if (!points.length) return;
tempContext.clearRect(0, 0, innerWidth, innerHeight);
var point = points[points.length - 1];
drawHelper[point[0]](context, point[1], point[2]);
},
dragAllPaths: function(x, y) {
var g = this.global,
prevX = g.prevX,
prevY = g.prevY,
p, point,
length = points.length,
getPoint = this.getPoint,
i = g.startingIndex;
for (i; i < length; i++) {
p = points[i];
point = p[1];
if (p[0] === 'line') {
points[i] = [p[0],
[
getPoint(x, prevX, point[0]),
getPoint(y, prevY, point[1]),
getPoint(x, prevX, point[2]),
getPoint(y, prevY, point[3])
], p[2]
];
}
if (p[0] === 'arrow') {
points[i] = [p[0],
[
getPoint(x, prevX, point[0]),
getPoint(y, prevY, point[1]),
getPoint(x, prevX, point[2]),
getPoint(y, prevY, point[3])
], p[2]
];
}
if (p[0] === 'text') {
points[i] = [p[0],
[
point[0],
getPoint(x, prevX, point[1]),
getPoint(y, prevY, point[2])
], p[2]
];
}
if (p[0] === 'arc') {
points[i] = [p[0],
[
getPoint(x, prevX, point[0]),
getPoint(y, prevY, point[1]),
point[2],
point[3],
point[4]
], p[2]
];
}
if (p[0] === 'rect') {
points[i] = [p[0],
[
getPoint(x, prevX, point[0]),
getPoint(y, prevY, point[1]),
point[2],
point[3]
], p[2]
];
}
if (p[0] === 'image') {
points[i] = [p[0],
[
point[0],
getPoint(x, prevX, point[1]),
getPoint(y, prevY, point[2]),
point[3],
point[4],
point[5]
], p[2]
];
}
if (p[0] === 'quadratic') {
points[i] = [p[0],
[
getPoint(x, prevX, point[0]),
getPoint(y, prevY, point[1]),
getPoint(x, prevX, point[2]),
getPoint(y, prevY, point[3]),
getPoint(x, prevX, point[4]),
getPoint(y, prevY, point[5])
], p[2]
];
}
if (p[0] === 'bezier') {
points[i] = [p[0],
[
getPoint(x, prevX, point[0]),
getPoint(y, prevY, point[1]),
getPoint(x, prevX, point[2]),
getPoint(y, prevY, point[3]),
getPoint(x, prevX, point[4]),
getPoint(y, prevY, point[5]),
getPoint(x, prevX, point[6]),
getPoint(y, prevY, point[7])
], p[2]
];
}
}
},
dragLastPath: function(x, y) {
var g = this.global,
prevX = g.prevX,
prevY = g.prevY,
p = points[points.length - 1],
point = p[1],
getPoint = this.getPoint,
getXYWidthHeight = this.getXYWidthHeight,
isMoveAllPoints = g.pointsToMove === 'all';
if (p[0] === 'line') {
if (g.pointsToMove === 'head' || isMoveAllPoints) {
point[0] = getPoint(x, prevX, point[0]);
point[1] = getPoint(y, prevY, point[1]);
}
if (g.pointsToMove === 'tail' || isMoveAllPoints) {
point[2] = getPoint(x, prevX, point[2]);
point[3] = getPoint(y, prevY, point[3]);
}
points[points.length - 1] = [p[0], point, p[2]];
}
if (p[0] === 'arrow') {
if (g.pointsToMove === 'head' || isMoveAllPoints) {
point[0] = getPoint(x, prevX, point[0]);
point[1] = getPoint(y, prevY, point[1]);
}
if (g.pointsToMove === 'tail' || isMoveAllPoints) {
point[2] = getPoint(x, prevX, point[2]);
point[3] = getPoint(y, prevY, point[3]);
}
points[points.length - 1] = [p[0], point, p[2]];
}
if (p[0] === 'text') {
if (g.pointsToMove === 'head' || isMoveAllPoints) {
point[1] = getPoint(x, prevX, point[1]);
point[2] = getPoint(y, prevY, point[2]);
}
points[points.length - 1] = [p[0], point, p[2]];
}
if (p[0] === 'arc') {
point[0] = getPoint(x, prevX, point[0]);
point[1] = getPoint(y, prevY, point[1]);
points[points.length - 1] = [p[0], point, p[2]];
}
if (p[0] === 'rect') {
if (isMoveAllPoints) {
point[0] = getPoint(x, prevX, point[0]);
point[1] = getPoint(y, prevY, point[1]);
}
if (g.pointsToMove === 'stretch-first') {
var newPoints = getXYWidthHeight(x, y, prevX, prevY, {
x: point[0],
y: point[1],
width: point[2],
height: point[3],
pointsToMove: g.pointsToMove
});
point[0] = newPoints.x;
point[1] = newPoints.y;
point[2] = newPoints.width;
point[3] = newPoints.height;
}
if (g.pointsToMove === 'stretch-second') {
var newPoints = getXYWidthHeight(x, y, prevX, prevY, {
x: point[0],
y: point[1],
width: point[2],
height: point[3],
pointsToMove: g.pointsToMove
});
point[1] = newPoints.y;
point[2] = newPoints.width;
point[3] = newPoints.height;
}
if (g.pointsToMove === 'stretch-third') {
var newPoints = getXYWidthHeight(x, y, prevX, prevY, {
x: point[0],
y: point[1],
width: point[2],
height: point[3],
pointsToMove: g.pointsToMove
});
point[0] = newPoints.x;
point[2] = newPoints.width;
point[3] = newPoints.height;
}
if (g.pointsToMove === 'stretch-last') {
point[2] = getPoint(x, prevX, point[2]);
point[3] = getPoint(y, prevY, point[3]);
}
points[points.length - 1] = [p[0], point, p[2]];