angular-canvas-painter
Advanced tools
Comparing version 0.5.2 to 0.5.3
{ | ||
"name": "angular-canvas-painter", | ||
"version": "0.5.2", | ||
"version": "0.5.3", | ||
"authors": [ | ||
@@ -5,0 +5,0 @@ "Philipp Wambach" |
@@ -0,1 +1,11 @@ | ||
<a name="0.5.3"></a> | ||
# 0.5.3 (2015-11-09) | ||
## Bug fixes | ||
- Fix mouseenter/leave problems in firefox (thanks @w3sami) | ||
([#17](https://github.com/pwambach/angular-canvas-painter/pull/20)) | ||
- Convert tabs to spaces | ||
<a name="0.5.2"></a> | ||
@@ -2,0 +12,0 @@ # 0.5.2 (2015-10-27) |
@@ -37,271 +37,298 @@ /*! | ||
angular.module('pw.canvas-painter') | ||
.directive('pwCanvas', function () { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
options: '=', | ||
version: '=' | ||
}, | ||
templateUrl: '../templates/canvas.html', | ||
link: function postLink(scope, elm) { | ||
.directive('pwCanvas', function() { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
options: '=', | ||
version: '=' | ||
}, | ||
templateUrl: '../templates/canvas.html', | ||
link: function postLink(scope, elm) { | ||
var isTouch = !!('ontouchstart' in window); | ||
var isTouch = !!('ontouchstart' in window); | ||
var PAINT_START = isTouch ? 'touchstart' : 'mousedown'; | ||
var PAINT_MOVE = isTouch ? 'touchmove' : 'mousemove'; | ||
var PAINT_END = isTouch ? 'touchend' : 'mouseup'; | ||
var PAINT_START = isTouch ? 'touchstart' : 'mousedown'; | ||
var PAINT_MOVE = isTouch ? 'touchmove' : 'mousemove'; | ||
var PAINT_END = isTouch ? 'touchend' : 'mouseup'; | ||
//set default options | ||
var options = scope.options; | ||
options.canvasId = options.customCanvasId || 'pwCanvasMain'; | ||
options.tmpCanvasId = options.customCanvasId ? (options.canvasId + 'Tmp') : 'pwCanvasTmp'; | ||
options.width = options.width || 400; | ||
options.height = options.height || 300; | ||
options.backgroundColor = options.backgroundColor || '#fff'; | ||
options.color = options.color || '#000'; | ||
options.undoEnabled = options.undoEnabled || false; | ||
options.opacity = options.opacity || 0.9; | ||
options.lineWidth = options.lineWidth || 1; | ||
options.undo = options.undo || false; | ||
options.imageSrc = options.imageSrc || false; | ||
//set default options | ||
var options = scope.options; | ||
options.canvasId = options.customCanvasId || 'pwCanvasMain'; | ||
options.tmpCanvasId = options.customCanvasId ? (options.canvasId + 'Tmp') : 'pwCanvasTmp'; | ||
options.width = options.width || 400; | ||
options.height = options.height || 300; | ||
options.backgroundColor = options.backgroundColor || '#fff'; | ||
options.color = options.color || '#000'; | ||
options.undoEnabled = options.undoEnabled || false; | ||
options.opacity = options.opacity || 0.9; | ||
options.lineWidth = options.lineWidth || 1; | ||
options.undo = options.undo || false; | ||
options.imageSrc = options.imageSrc || false; | ||
// background image | ||
if(options.imageSrc){ | ||
var image = new Image(); | ||
image.onload = function(){ | ||
ctx.drawImage(this, 0, 0); | ||
}; | ||
image.src = options.imageSrc; | ||
} | ||
// background image | ||
if (options.imageSrc) { | ||
var image = new Image(); | ||
image.onload = function() { | ||
ctx.drawImage(this, 0, 0); | ||
}; | ||
image.src = options.imageSrc; | ||
} | ||
//undo | ||
if(options.undo){ | ||
var undoCache = []; | ||
scope.$watch(function(){ | ||
return undoCache.length; | ||
}, function(newVal){ | ||
scope.version = newVal; | ||
}); | ||
//undo | ||
if (options.undo) { | ||
var undoCache = []; | ||
scope.$watch(function() { | ||
return undoCache.length; | ||
}, function(newVal) { | ||
scope.version = newVal; | ||
}); | ||
scope.$watch('version', function(newVal){ | ||
if(newVal < 0){ | ||
scope.version = 0; | ||
return; | ||
} | ||
if(newVal >= undoCache.length){ | ||
scope.version = undoCache.length; | ||
return; | ||
} | ||
undo(newVal); | ||
}); | ||
} | ||
scope.$watch('version', function(newVal) { | ||
if (newVal < 0) { | ||
scope.version = 0; | ||
return; | ||
} | ||
if (newVal >= undoCache.length) { | ||
scope.version = undoCache.length; | ||
return; | ||
} | ||
undo(newVal); | ||
}); | ||
} | ||
//create canvas and context | ||
var canvas = document.createElement('canvas'); | ||
canvas.id = options.canvasId; | ||
var canvasTmp = document.createElement('canvas'); | ||
canvasTmp.id = options.tmpCanvasId; | ||
angular.element(canvasTmp).css({ | ||
position: 'absolute', | ||
top: 0, | ||
left: 0 | ||
}); | ||
elm.find('div').append(canvas); | ||
elm.find('div').append(canvasTmp); | ||
var ctx = canvas.getContext('2d'); | ||
var ctxTmp = canvasTmp.getContext('2d'); | ||
//create canvas and context | ||
var canvas = document.createElement('canvas'); | ||
canvas.id = options.canvasId; | ||
var canvasTmp = document.createElement('canvas'); | ||
canvasTmp.id = options.tmpCanvasId; | ||
angular.element(canvasTmp).css({ | ||
position: 'absolute', | ||
top: 0, | ||
left: 0 | ||
}); | ||
elm.find('div').append(canvas); | ||
elm.find('div').append(canvasTmp); | ||
var ctx = canvas.getContext('2d'); | ||
var ctxTmp = canvasTmp.getContext('2d'); | ||
//inti variables | ||
var point = {x: 0, y: 0}; | ||
var ppts = []; | ||
//inti variables | ||
var point = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
var ppts = []; | ||
//set canvas size | ||
canvas.width = canvasTmp.width = options.width; | ||
canvas.height = canvasTmp.height = options.height; | ||
//set canvas size | ||
canvas.width = canvasTmp.width = options.width; | ||
canvas.height = canvasTmp.height = options.height; | ||
//set context style | ||
ctx.fillStyle = options.backgroundColor; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
ctxTmp.globalAlpha = options.opacity; | ||
ctxTmp.lineJoin = ctxTmp.lineCap = 'round'; | ||
ctxTmp.lineWidth = 10; | ||
ctxTmp.strokeStyle = options.color; | ||
//set context style | ||
ctx.fillStyle = options.backgroundColor; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
ctxTmp.globalAlpha = options.opacity; | ||
ctxTmp.lineJoin = ctxTmp.lineCap = 'round'; | ||
ctxTmp.lineWidth = 10; | ||
ctxTmp.strokeStyle = options.color; | ||
//Watch options | ||
scope.$watch('options.lineWidth', function(newValue){ | ||
if(typeof newValue === 'string'){ | ||
newValue = parseInt(newValue, 10); | ||
} | ||
if(newValue && typeof newValue === 'number'){ | ||
ctxTmp.lineWidth = options.lineWidth = newValue; | ||
} | ||
}); | ||
//Watch options | ||
scope.$watch('options.lineWidth', function(newValue) { | ||
if (typeof newValue === 'string') { | ||
newValue = parseInt(newValue, 10); | ||
} | ||
if (newValue && typeof newValue === 'number') { | ||
ctxTmp.lineWidth = options.lineWidth = newValue; | ||
} | ||
}); | ||
scope.$watch('options.color', function(newValue){ | ||
if(newValue){ | ||
//ctx.fillStyle = newValue; | ||
ctxTmp.strokeStyle = ctxTmp.fillStyle = newValue; | ||
} | ||
}); | ||
scope.$watch('options.color', function(newValue) { | ||
if (newValue) { | ||
//ctx.fillStyle = newValue; | ||
ctxTmp.strokeStyle = ctxTmp.fillStyle = newValue; | ||
} | ||
}); | ||
scope.$watch('options.opacity', function(newValue){ | ||
if(newValue){ | ||
ctxTmp.globalAlpha = newValue; | ||
} | ||
}); | ||
scope.$watch('options.opacity', function(newValue) { | ||
if (newValue) { | ||
ctxTmp.globalAlpha = newValue; | ||
} | ||
}); | ||
var getOffset = function(elem) { | ||
var offsetTop = 0; | ||
var offsetLeft = 0; | ||
do { | ||
if (!isNaN(elem.offsetLeft)) { | ||
offsetTop += elem.offsetTop; | ||
offsetLeft += elem.offsetLeft; | ||
} | ||
elem = elem.offsetParent; | ||
} while (elem); | ||
return { | ||
left: offsetLeft, | ||
top: offsetTop | ||
}; | ||
}; | ||
/* var clearCanvas = function(){ | ||
ctx.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
};*/ | ||
var setPointFromEvent = function(point, e) { | ||
if (isTouch) { | ||
point.x = e.changedTouches[0].pageX - getOffset(e.target).left; | ||
point.y = e.changedTouches[0].pageY - getOffset(e.target).top; | ||
} else { | ||
point.x = e.offsetX !== undefined ? e.offsetX : e.layerX; | ||
point.y = e.offsetY !== undefined ? e.offsetY : e.layerY; | ||
} | ||
}; | ||
var getOffset = function( elem ) { | ||
var offsetTop = 0; | ||
var offsetLeft = 0; | ||
do { | ||
if ( !isNaN( elem.offsetLeft ) ) | ||
{ | ||
offsetTop += elem.offsetTop; | ||
offsetLeft += elem.offsetLeft; | ||
} | ||
elem = elem.offsetParent; | ||
} while( elem ); | ||
return { | ||
left:offsetLeft, | ||
top: offsetTop | ||
}; | ||
}; | ||
var setPointFromEvent = function(point, e) { | ||
if(isTouch){ | ||
point.x = e.changedTouches[0].pageX - getOffset(e.target).left; | ||
point.y = e.changedTouches[0].pageY - getOffset(e.target).top; | ||
} else { | ||
point.x = e.offsetX !== undefined ? e.offsetX : e.layerX; | ||
point.y = e.offsetY !== undefined ? e.offsetY : e.layerY; | ||
} | ||
}; | ||
var paint = function(e) { | ||
if (e) { | ||
e.preventDefault(); | ||
setPointFromEvent(point, e); | ||
} | ||
// Saving all the points in an array | ||
ppts.push({ | ||
x: point.x, | ||
y: point.y | ||
}); | ||
var paint = function (e){ | ||
if(e){ | ||
e.preventDefault(); | ||
setPointFromEvent(point, e); | ||
} | ||
if (ppts.length === 3) { | ||
var b = ppts[0]; | ||
ctxTmp.beginPath(); | ||
ctxTmp.arc(b.x, b.y, ctxTmp.lineWidth / 2, 0, Math.PI * 2, !0); | ||
ctxTmp.fill(); | ||
ctxTmp.closePath(); | ||
return; | ||
} | ||
// Saving all the points in an array | ||
ppts.push({x: point.x, y: point.y}); | ||
// Tmp canvas is always cleared up before drawing. | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
if (ppts.length === 3) { | ||
var b = ppts[0]; | ||
ctxTmp.beginPath(); | ||
ctxTmp.arc(b.x, b.y, ctxTmp.lineWidth / 2, 0, Math.PI * 2, !0); | ||
ctxTmp.fill(); | ||
ctxTmp.closePath(); | ||
return; | ||
} | ||
ctxTmp.beginPath(); | ||
ctxTmp.moveTo(ppts[0].x, ppts[0].y); | ||
// Tmp canvas is always cleared up before drawing. | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
for (var i = 1; i < ppts.length - 2; i++) { | ||
var c = (ppts[i].x + ppts[i + 1].x) / 2; | ||
var d = (ppts[i].y + ppts[i + 1].y) / 2; | ||
ctxTmp.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d); | ||
} | ||
ctxTmp.beginPath(); | ||
ctxTmp.moveTo(ppts[0].x, ppts[0].y); | ||
// For the last 2 points | ||
ctxTmp.quadraticCurveTo( | ||
ppts[i].x, | ||
ppts[i].y, | ||
ppts[i + 1].x, | ||
ppts[i + 1].y | ||
); | ||
ctxTmp.stroke(); | ||
}; | ||
for (var i = 1; i < ppts.length - 2; i++) { | ||
var c = (ppts[i].x + ppts[i + 1].x) / 2; | ||
var d = (ppts[i].y + ppts[i + 1].y) / 2; | ||
ctxTmp.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d); | ||
} | ||
var copyTmpImage = function() { | ||
if (options.undo) { | ||
scope.$apply(function() { | ||
undoCache.push(ctx.getImageData(0, 0, canvasTmp.width, canvasTmp.height)); | ||
if (angular.isNumber(options.undo) && options.undo > 0) { | ||
undoCache = undoCache.slice(-1 * options.undo); | ||
} | ||
}); | ||
} | ||
canvasTmp.removeEventListener(PAINT_MOVE, paint, false); | ||
ctx.drawImage(canvasTmp, 0, 0); | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
ppts = []; | ||
}; | ||
// For the last 2 points | ||
ctxTmp.quadraticCurveTo( | ||
ppts[i].x, | ||
ppts[i].y, | ||
ppts[i + 1].x, | ||
ppts[i + 1].y | ||
); | ||
ctxTmp.stroke(); | ||
}; | ||
var startTmpImage = function(e) { | ||
e.preventDefault(); | ||
canvasTmp.addEventListener(PAINT_MOVE, paint, false); | ||
var copyTmpImage = function(){ | ||
if(options.undo){ | ||
scope.$apply(function(){ | ||
undoCache.push(ctx.getImageData(0, 0, canvasTmp.width, canvasTmp.height)); | ||
if(angular.isNumber(options.undo) && options.undo > 0){ | ||
undoCache = undoCache.slice(-1 * options.undo); | ||
} | ||
}); | ||
} | ||
canvasTmp.removeEventListener(PAINT_MOVE, paint, false); | ||
ctx.drawImage(canvasTmp, 0, 0); | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
ppts = []; | ||
}; | ||
setPointFromEvent(point, e); | ||
ppts.push({ | ||
x: point.x, | ||
y: point.y | ||
}); | ||
ppts.push({ | ||
x: point.x, | ||
y: point.y | ||
}); | ||
var startTmpImage = function(e){ | ||
e.preventDefault(); | ||
canvasTmp.addEventListener(PAINT_MOVE, paint, false); | ||
paint(); | ||
}; | ||
setPointFromEvent(point, e); | ||
ppts.push({x: point.x, y: point.y}); | ||
ppts.push({x: point.x, y: point.y}); | ||
var initListeners = function() { | ||
canvasTmp.addEventListener(PAINT_START, startTmpImage, false); | ||
canvasTmp.addEventListener(PAINT_END, copyTmpImage, false); | ||
paint(); | ||
}; | ||
if (!isTouch) { | ||
var MOUSE_DOWN; | ||
var initListeners = function(){ | ||
canvasTmp.addEventListener(PAINT_START, startTmpImage, false); | ||
canvasTmp.addEventListener(PAINT_END, copyTmpImage, false); | ||
document.body.addEventListener('mousedown', mousedown); | ||
document.body.addEventListener('mouseup', mouseup); | ||
if(!isTouch){ | ||
canvasTmp.addEventListener('mouseenter', function(e){ | ||
// If the mouse is down when it enters the canvas, start a path | ||
if(e.which === 1){ | ||
startTmpImage(e); | ||
} | ||
}, false); | ||
canvasTmp.addEventListener('mouseleave', function(e){ | ||
// If the mouse is down when it leaves the canvas, end the path | ||
if(e.which === 1){ | ||
copyTmpImage(e); | ||
} | ||
}, false); | ||
} | ||
}; | ||
initListeners(); | ||
scope.$on('$destroy', removeEventListeners); | ||
canvasTmp.addEventListener('mouseenter', mouseenter); | ||
canvasTmp.addEventListener('mouseleave', mouseleave); | ||
} | ||
function mousedown() { | ||
MOUSE_DOWN = true; | ||
} | ||
var undo = function(version){ | ||
if(undoCache.length > 0){ | ||
ctx.putImageData(undoCache[version], 0, 0); | ||
undoCache = undoCache.slice(0,version); | ||
} | ||
}; | ||
function mouseup() { | ||
MOUSE_DOWN = false; | ||
} | ||
} | ||
}; | ||
}); | ||
function removeEventListeners() { | ||
document.body.removeEventListener('mousedown', mousedown); | ||
document.body.removeEventListener('mouseup', mouseup); | ||
} | ||
function mouseenter(e) { | ||
// If the mouse is down when it enters the canvas, start a path | ||
if (MOUSE_DOWN) { | ||
startTmpImage(e); | ||
} | ||
} | ||
function mouseleave(e) { | ||
// If the mouse is down when it leaves the canvas, end the path | ||
if (MOUSE_DOWN) { | ||
copyTmpImage(e); | ||
} | ||
} | ||
}; | ||
var undo = function(version) { | ||
if (undoCache.length > 0) { | ||
ctx.putImageData(undoCache[version], 0, 0); | ||
undoCache = undoCache.slice(0, version); | ||
} | ||
}; | ||
initListeners(); | ||
} | ||
}; | ||
}); | ||
angular.module('pw.canvas-painter') | ||
.directive('pwColorSelector', function () { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
colorList: '=pwColorSelector', | ||
selectedColor: '=color' | ||
}, | ||
templateUrl: '../templates/color-selector.html', | ||
link: function(scope){ | ||
scope.setColor = function(col){ | ||
scope.selectedColor = col; | ||
}; | ||
} | ||
}; | ||
}); | ||
.directive('pwColorSelector', function () { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
colorList: '=pwColorSelector', | ||
selectedColor: '=color' | ||
}, | ||
templateUrl: '../templates/color-selector.html', | ||
link: function(scope){ | ||
scope.setColor = function(col){ | ||
scope.selectedColor = col; | ||
}; | ||
} | ||
}; | ||
}); | ||
}(this)); |
@@ -1,1 +0,1 @@ | ||
"use strict";!function(t){angular.module("pw.canvas-painter",[]),function(t){try{t=angular.module("pw.canvas-painter")}catch(e){t=angular.module("pw.canvas-painter",[])}t.run(["$templateCache",function(t){t.put("../templates/canvas.html",'<div class="pwCanvasPaint" style="position:relative"></div>')}])}(),function(t){try{t=angular.module("pw.canvas-painter")}catch(e){t=angular.module("pw.canvas-painter",[])}t.run(["$templateCache",function(t){t.put("../templates/color-selector.html",'<ul class="pwColorSelector"><li ng-repeat="color in colorList track by $index" class="pwColor" ng-class="{\'active\': (selectedColor === color)}" ng-style="{\'background-color\':color}" ng-click="setColor(color)"></li></ul>')}])}(),angular.module("pw.canvas-painter").directive("pwCanvas",function(){return{restrict:"AE",scope:{options:"=",version:"="},templateUrl:"../templates/canvas.html",link:function(e,n){var o=!!("ontouchstart"in t),a=o?"touchstart":"mousedown",i=o?"touchmove":"mousemove",r=o?"touchend":"mouseup",l=e.options;if(l.canvasId=l.customCanvasId||"pwCanvasMain",l.tmpCanvasId=l.customCanvasId?l.canvasId+"Tmp":"pwCanvasTmp",l.width=l.width||400,l.height=l.height||300,l.backgroundColor=l.backgroundColor||"#fff",l.color=l.color||"#000",l.undoEnabled=l.undoEnabled||!1,l.opacity=l.opacity||.9,l.lineWidth=l.lineWidth||1,l.undo=l.undo||!1,l.imageSrc=l.imageSrc||!1,l.imageSrc){var c=new Image;c.onload=function(){h.drawImage(this,0,0)},c.src=l.imageSrc}if(l.undo){var s=[];e.$watch(function(){return s.length},function(t){e.version=t}),e.$watch("version",function(t){return 0>t?(e.version=0,void 0):t>=s.length?(e.version=s.length,void 0):(b(t),void 0)})}var u=document.createElement("canvas");u.id=l.canvasId;var d=document.createElement("canvas");d.id=l.tmpCanvasId,angular.element(d).css({position:"absolute",top:0,left:0}),n.find("div").append(u),n.find("div").append(d);var h=u.getContext("2d"),p=d.getContext("2d"),v={x:0,y:0},f=[];u.width=d.width=l.width,u.height=d.height=l.height,h.fillStyle=l.backgroundColor,h.fillRect(0,0,u.width,u.height),p.globalAlpha=l.opacity,p.lineJoin=p.lineCap="round",p.lineWidth=10,p.strokeStyle=l.color,e.$watch("options.lineWidth",function(t){"string"==typeof t&&(t=parseInt(t,10)),t&&"number"==typeof t&&(p.lineWidth=l.lineWidth=t)}),e.$watch("options.color",function(t){t&&(p.strokeStyle=p.fillStyle=t)}),e.$watch("options.opacity",function(t){t&&(p.globalAlpha=t)});var g=function(t){var e=0,n=0;do isNaN(t.offsetLeft)||(e+=t.offsetTop,n+=t.offsetLeft),t=t.offsetParent;while(t);return{left:n,top:e}},m=function(t,e){o?(t.x=e.changedTouches[0].pageX-g(e.target).left,t.y=e.changedTouches[0].pageY-g(e.target).top):(t.x=void 0!==e.offsetX?e.offsetX:e.layerX,t.y=void 0!==e.offsetY?e.offsetY:e.layerY)},w=function(t){if(t&&(t.preventDefault(),m(v,t)),f.push({x:v.x,y:v.y}),3===f.length){var e=f[0];return p.beginPath(),p.arc(e.x,e.y,p.lineWidth/2,0,2*Math.PI,!0),p.fill(),p.closePath(),void 0}p.clearRect(0,0,d.width,d.height),p.beginPath(),p.moveTo(f[0].x,f[0].y);for(var n=1;n<f.length-2;n++){var o=(f[n].x+f[n+1].x)/2,a=(f[n].y+f[n+1].y)/2;p.quadraticCurveTo(f[n].x,f[n].y,o,a)}p.quadraticCurveTo(f[n].x,f[n].y,f[n+1].x,f[n+1].y),p.stroke()},y=function(){l.undo&&e.$apply(function(){s.push(h.getImageData(0,0,d.width,d.height)),angular.isNumber(l.undo)&&l.undo>0&&(s=s.slice(-1*l.undo))}),d.removeEventListener(i,w,!1),h.drawImage(d,0,0),p.clearRect(0,0,d.width,d.height),f=[]},C=function(t){t.preventDefault(),d.addEventListener(i,w,!1),m(v,t),f.push({x:v.x,y:v.y}),f.push({x:v.x,y:v.y}),w()},x=function(){d.addEventListener(a,C,!1),d.addEventListener(r,y,!1),o||(d.addEventListener("mouseenter",function(t){1===t.which&&C(t)},!1),d.addEventListener("mouseleave",function(t){1===t.which&&y(t)},!1))};x();var b=function(t){s.length>0&&(h.putImageData(s[t],0,0),s=s.slice(0,t))}}}}),angular.module("pw.canvas-painter").directive("pwColorSelector",function(){return{restrict:"AE",scope:{colorList:"=pwColorSelector",selectedColor:"=color"},templateUrl:"../templates/color-selector.html",link:function(t){t.setColor=function(e){t.selectedColor=e}}}})}(this); | ||
"use strict";!function(e){angular.module("pw.canvas-painter",[]),function(e){try{e=angular.module("pw.canvas-painter")}catch(t){e=angular.module("pw.canvas-painter",[])}e.run(["$templateCache",function(e){e.put("../templates/canvas.html",'<div class="pwCanvasPaint" style="position:relative"></div>')}])}(),function(e){try{e=angular.module("pw.canvas-painter")}catch(t){e=angular.module("pw.canvas-painter",[])}e.run(["$templateCache",function(e){e.put("../templates/color-selector.html",'<ul class="pwColorSelector"><li ng-repeat="color in colorList track by $index" class="pwColor" ng-class="{\'active\': (selectedColor === color)}" ng-style="{\'background-color\':color}" ng-click="setColor(color)"></li></ul>')}])}(),angular.module("pw.canvas-painter").directive("pwCanvas",function(){return{restrict:"AE",scope:{options:"=",version:"="},templateUrl:"../templates/canvas.html",link:function(t,n){var o=!!("ontouchstart"in e),a=o?"touchstart":"mousedown",i=o?"touchmove":"mousemove",r=o?"touchend":"mouseup",c=t.options;if(c.canvasId=c.customCanvasId||"pwCanvasMain",c.tmpCanvasId=c.customCanvasId?c.canvasId+"Tmp":"pwCanvasTmp",c.width=c.width||400,c.height=c.height||300,c.backgroundColor=c.backgroundColor||"#fff",c.color=c.color||"#000",c.undoEnabled=c.undoEnabled||!1,c.opacity=c.opacity||.9,c.lineWidth=c.lineWidth||1,c.undo=c.undo||!1,c.imageSrc=c.imageSrc||!1,c.imageSrc){var l=new Image;l.onload=function(){p.drawImage(this,0,0)},l.src=c.imageSrc}if(c.undo){var s=[];t.$watch(function(){return s.length},function(e){t.version=e}),t.$watch("version",function(e){return 0>e?(t.version=0,void 0):e>=s.length?(t.version=s.length,void 0):(b(e),void 0)})}var u=document.createElement("canvas");u.id=c.canvasId;var d=document.createElement("canvas");d.id=c.tmpCanvasId,angular.element(d).css({position:"absolute",top:0,left:0}),n.find("div").append(u),n.find("div").append(d);var p=u.getContext("2d"),h=d.getContext("2d"),v={x:0,y:0},f=[];u.width=d.width=c.width,u.height=d.height=c.height,p.fillStyle=c.backgroundColor,p.fillRect(0,0,u.width,u.height),h.globalAlpha=c.opacity,h.lineJoin=h.lineCap="round",h.lineWidth=10,h.strokeStyle=c.color,t.$watch("options.lineWidth",function(e){"string"==typeof e&&(e=parseInt(e,10)),e&&"number"==typeof e&&(h.lineWidth=c.lineWidth=e)}),t.$watch("options.color",function(e){e&&(h.strokeStyle=h.fillStyle=e)}),t.$watch("options.opacity",function(e){e&&(h.globalAlpha=e)});var m=function(e){var t=0,n=0;do isNaN(e.offsetLeft)||(t+=e.offsetTop,n+=e.offsetLeft),e=e.offsetParent;while(e);return{left:n,top:t}},g=function(e,t){o?(e.x=t.changedTouches[0].pageX-m(t.target).left,e.y=t.changedTouches[0].pageY-m(t.target).top):(e.x=void 0!==t.offsetX?t.offsetX:t.layerX,e.y=void 0!==t.offsetY?t.offsetY:t.layerY)},y=function(e){if(e&&(e.preventDefault(),g(v,e)),f.push({x:v.x,y:v.y}),3===f.length){var t=f[0];return h.beginPath(),h.arc(t.x,t.y,h.lineWidth/2,0,2*Math.PI,!0),h.fill(),h.closePath(),void 0}h.clearRect(0,0,d.width,d.height),h.beginPath(),h.moveTo(f[0].x,f[0].y);for(var n=1;n<f.length-2;n++){var o=(f[n].x+f[n+1].x)/2,a=(f[n].y+f[n+1].y)/2;h.quadraticCurveTo(f[n].x,f[n].y,o,a)}h.quadraticCurveTo(f[n].x,f[n].y,f[n+1].x,f[n+1].y),h.stroke()},w=function(){c.undo&&t.$apply(function(){s.push(p.getImageData(0,0,d.width,d.height)),angular.isNumber(c.undo)&&c.undo>0&&(s=s.slice(-1*c.undo))}),d.removeEventListener(i,y,!1),p.drawImage(d,0,0),h.clearRect(0,0,d.width,d.height),f=[]},C=function(e){e.preventDefault(),d.addEventListener(i,y,!1),g(v,e),f.push({x:v.x,y:v.y}),f.push({x:v.x,y:v.y}),y()},x=function(){function e(){s=!0}function n(){s=!1}function i(){document.body.removeEventListener("mousedown",e),document.body.removeEventListener("mouseup",n)}function c(e){s&&C(e)}function l(e){s&&w(e)}if(d.addEventListener(a,C,!1),d.addEventListener(r,w,!1),!o){var s;document.body.addEventListener("mousedown",e),document.body.addEventListener("mouseup",n),t.$on("$destroy",i),d.addEventListener("mouseenter",c),d.addEventListener("mouseleave",l)}},b=function(e){s.length>0&&(p.putImageData(s[e],0,0),s=s.slice(0,e))};x()}}}),angular.module("pw.canvas-painter").directive("pwColorSelector",function(){return{restrict:"AE",scope:{colorList:"=pwColorSelector",selectedColor:"=color"},templateUrl:"../templates/color-selector.html",link:function(e){e.setColor=function(t){e.selectedColor=t}}}})}(this); |
'use strict'; | ||
angular.module('pw.canvas-painter') | ||
.directive('pwCanvas', function () { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
options: '=', | ||
version: '=' | ||
}, | ||
templateUrl: '../templates/canvas.html', | ||
link: function postLink(scope, elm) { | ||
.directive('pwCanvas', function() { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
options: '=', | ||
version: '=' | ||
}, | ||
templateUrl: '../templates/canvas.html', | ||
link: function postLink(scope, elm) { | ||
var isTouch = !!('ontouchstart' in window); | ||
var isTouch = !!('ontouchstart' in window); | ||
var PAINT_START = isTouch ? 'touchstart' : 'mousedown'; | ||
var PAINT_MOVE = isTouch ? 'touchmove' : 'mousemove'; | ||
var PAINT_END = isTouch ? 'touchend' : 'mouseup'; | ||
var PAINT_START = isTouch ? 'touchstart' : 'mousedown'; | ||
var PAINT_MOVE = isTouch ? 'touchmove' : 'mousemove'; | ||
var PAINT_END = isTouch ? 'touchend' : 'mouseup'; | ||
//set default options | ||
var options = scope.options; | ||
options.canvasId = options.customCanvasId || 'pwCanvasMain'; | ||
options.tmpCanvasId = options.customCanvasId ? (options.canvasId + 'Tmp') : 'pwCanvasTmp'; | ||
options.width = options.width || 400; | ||
options.height = options.height || 300; | ||
options.backgroundColor = options.backgroundColor || '#fff'; | ||
options.color = options.color || '#000'; | ||
options.undoEnabled = options.undoEnabled || false; | ||
options.opacity = options.opacity || 0.9; | ||
options.lineWidth = options.lineWidth || 1; | ||
options.undo = options.undo || false; | ||
options.imageSrc = options.imageSrc || false; | ||
//set default options | ||
var options = scope.options; | ||
options.canvasId = options.customCanvasId || 'pwCanvasMain'; | ||
options.tmpCanvasId = options.customCanvasId ? (options.canvasId + 'Tmp') : 'pwCanvasTmp'; | ||
options.width = options.width || 400; | ||
options.height = options.height || 300; | ||
options.backgroundColor = options.backgroundColor || '#fff'; | ||
options.color = options.color || '#000'; | ||
options.undoEnabled = options.undoEnabled || false; | ||
options.opacity = options.opacity || 0.9; | ||
options.lineWidth = options.lineWidth || 1; | ||
options.undo = options.undo || false; | ||
options.imageSrc = options.imageSrc || false; | ||
// background image | ||
if(options.imageSrc){ | ||
var image = new Image(); | ||
image.onload = function(){ | ||
ctx.drawImage(this, 0, 0); | ||
}; | ||
image.src = options.imageSrc; | ||
} | ||
// background image | ||
if (options.imageSrc) { | ||
var image = new Image(); | ||
image.onload = function() { | ||
ctx.drawImage(this, 0, 0); | ||
}; | ||
image.src = options.imageSrc; | ||
} | ||
//undo | ||
if(options.undo){ | ||
var undoCache = []; | ||
scope.$watch(function(){ | ||
return undoCache.length; | ||
}, function(newVal){ | ||
scope.version = newVal; | ||
}); | ||
//undo | ||
if (options.undo) { | ||
var undoCache = []; | ||
scope.$watch(function() { | ||
return undoCache.length; | ||
}, function(newVal) { | ||
scope.version = newVal; | ||
}); | ||
scope.$watch('version', function(newVal){ | ||
if(newVal < 0){ | ||
scope.version = 0; | ||
return; | ||
} | ||
if(newVal >= undoCache.length){ | ||
scope.version = undoCache.length; | ||
return; | ||
} | ||
undo(newVal); | ||
}); | ||
} | ||
scope.$watch('version', function(newVal) { | ||
if (newVal < 0) { | ||
scope.version = 0; | ||
return; | ||
} | ||
if (newVal >= undoCache.length) { | ||
scope.version = undoCache.length; | ||
return; | ||
} | ||
undo(newVal); | ||
}); | ||
} | ||
//create canvas and context | ||
var canvas = document.createElement('canvas'); | ||
canvas.id = options.canvasId; | ||
var canvasTmp = document.createElement('canvas'); | ||
canvasTmp.id = options.tmpCanvasId; | ||
angular.element(canvasTmp).css({ | ||
position: 'absolute', | ||
top: 0, | ||
left: 0 | ||
}); | ||
elm.find('div').append(canvas); | ||
elm.find('div').append(canvasTmp); | ||
var ctx = canvas.getContext('2d'); | ||
var ctxTmp = canvasTmp.getContext('2d'); | ||
//create canvas and context | ||
var canvas = document.createElement('canvas'); | ||
canvas.id = options.canvasId; | ||
var canvasTmp = document.createElement('canvas'); | ||
canvasTmp.id = options.tmpCanvasId; | ||
angular.element(canvasTmp).css({ | ||
position: 'absolute', | ||
top: 0, | ||
left: 0 | ||
}); | ||
elm.find('div').append(canvas); | ||
elm.find('div').append(canvasTmp); | ||
var ctx = canvas.getContext('2d'); | ||
var ctxTmp = canvasTmp.getContext('2d'); | ||
//inti variables | ||
var point = {x: 0, y: 0}; | ||
var ppts = []; | ||
//inti variables | ||
var point = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
var ppts = []; | ||
//set canvas size | ||
canvas.width = canvasTmp.width = options.width; | ||
canvas.height = canvasTmp.height = options.height; | ||
//set canvas size | ||
canvas.width = canvasTmp.width = options.width; | ||
canvas.height = canvasTmp.height = options.height; | ||
//set context style | ||
ctx.fillStyle = options.backgroundColor; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
ctxTmp.globalAlpha = options.opacity; | ||
ctxTmp.lineJoin = ctxTmp.lineCap = 'round'; | ||
ctxTmp.lineWidth = 10; | ||
ctxTmp.strokeStyle = options.color; | ||
//set context style | ||
ctx.fillStyle = options.backgroundColor; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
ctxTmp.globalAlpha = options.opacity; | ||
ctxTmp.lineJoin = ctxTmp.lineCap = 'round'; | ||
ctxTmp.lineWidth = 10; | ||
ctxTmp.strokeStyle = options.color; | ||
//Watch options | ||
scope.$watch('options.lineWidth', function(newValue){ | ||
if(typeof newValue === 'string'){ | ||
newValue = parseInt(newValue, 10); | ||
} | ||
if(newValue && typeof newValue === 'number'){ | ||
ctxTmp.lineWidth = options.lineWidth = newValue; | ||
} | ||
}); | ||
//Watch options | ||
scope.$watch('options.lineWidth', function(newValue) { | ||
if (typeof newValue === 'string') { | ||
newValue = parseInt(newValue, 10); | ||
} | ||
if (newValue && typeof newValue === 'number') { | ||
ctxTmp.lineWidth = options.lineWidth = newValue; | ||
} | ||
}); | ||
scope.$watch('options.color', function(newValue){ | ||
if(newValue){ | ||
//ctx.fillStyle = newValue; | ||
ctxTmp.strokeStyle = ctxTmp.fillStyle = newValue; | ||
} | ||
}); | ||
scope.$watch('options.color', function(newValue) { | ||
if (newValue) { | ||
//ctx.fillStyle = newValue; | ||
ctxTmp.strokeStyle = ctxTmp.fillStyle = newValue; | ||
} | ||
}); | ||
scope.$watch('options.opacity', function(newValue){ | ||
if(newValue){ | ||
ctxTmp.globalAlpha = newValue; | ||
} | ||
}); | ||
scope.$watch('options.opacity', function(newValue) { | ||
if (newValue) { | ||
ctxTmp.globalAlpha = newValue; | ||
} | ||
}); | ||
var getOffset = function(elem) { | ||
var offsetTop = 0; | ||
var offsetLeft = 0; | ||
do { | ||
if (!isNaN(elem.offsetLeft)) { | ||
offsetTop += elem.offsetTop; | ||
offsetLeft += elem.offsetLeft; | ||
} | ||
elem = elem.offsetParent; | ||
} while (elem); | ||
return { | ||
left: offsetLeft, | ||
top: offsetTop | ||
}; | ||
}; | ||
/* var clearCanvas = function(){ | ||
ctx.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
};*/ | ||
var setPointFromEvent = function(point, e) { | ||
if (isTouch) { | ||
point.x = e.changedTouches[0].pageX - getOffset(e.target).left; | ||
point.y = e.changedTouches[0].pageY - getOffset(e.target).top; | ||
} else { | ||
point.x = e.offsetX !== undefined ? e.offsetX : e.layerX; | ||
point.y = e.offsetY !== undefined ? e.offsetY : e.layerY; | ||
} | ||
}; | ||
var getOffset = function( elem ) { | ||
var offsetTop = 0; | ||
var offsetLeft = 0; | ||
do { | ||
if ( !isNaN( elem.offsetLeft ) ) | ||
{ | ||
offsetTop += elem.offsetTop; | ||
offsetLeft += elem.offsetLeft; | ||
} | ||
elem = elem.offsetParent; | ||
} while( elem ); | ||
return { | ||
left:offsetLeft, | ||
top: offsetTop | ||
}; | ||
}; | ||
var setPointFromEvent = function(point, e) { | ||
if(isTouch){ | ||
point.x = e.changedTouches[0].pageX - getOffset(e.target).left; | ||
point.y = e.changedTouches[0].pageY - getOffset(e.target).top; | ||
} else { | ||
point.x = e.offsetX !== undefined ? e.offsetX : e.layerX; | ||
point.y = e.offsetY !== undefined ? e.offsetY : e.layerY; | ||
} | ||
}; | ||
var paint = function(e) { | ||
if (e) { | ||
e.preventDefault(); | ||
setPointFromEvent(point, e); | ||
} | ||
// Saving all the points in an array | ||
ppts.push({ | ||
x: point.x, | ||
y: point.y | ||
}); | ||
var paint = function (e){ | ||
if(e){ | ||
e.preventDefault(); | ||
setPointFromEvent(point, e); | ||
} | ||
if (ppts.length === 3) { | ||
var b = ppts[0]; | ||
ctxTmp.beginPath(); | ||
ctxTmp.arc(b.x, b.y, ctxTmp.lineWidth / 2, 0, Math.PI * 2, !0); | ||
ctxTmp.fill(); | ||
ctxTmp.closePath(); | ||
return; | ||
} | ||
// Saving all the points in an array | ||
ppts.push({x: point.x, y: point.y}); | ||
// Tmp canvas is always cleared up before drawing. | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
if (ppts.length === 3) { | ||
var b = ppts[0]; | ||
ctxTmp.beginPath(); | ||
ctxTmp.arc(b.x, b.y, ctxTmp.lineWidth / 2, 0, Math.PI * 2, !0); | ||
ctxTmp.fill(); | ||
ctxTmp.closePath(); | ||
return; | ||
} | ||
ctxTmp.beginPath(); | ||
ctxTmp.moveTo(ppts[0].x, ppts[0].y); | ||
// Tmp canvas is always cleared up before drawing. | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
for (var i = 1; i < ppts.length - 2; i++) { | ||
var c = (ppts[i].x + ppts[i + 1].x) / 2; | ||
var d = (ppts[i].y + ppts[i + 1].y) / 2; | ||
ctxTmp.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d); | ||
} | ||
ctxTmp.beginPath(); | ||
ctxTmp.moveTo(ppts[0].x, ppts[0].y); | ||
// For the last 2 points | ||
ctxTmp.quadraticCurveTo( | ||
ppts[i].x, | ||
ppts[i].y, | ||
ppts[i + 1].x, | ||
ppts[i + 1].y | ||
); | ||
ctxTmp.stroke(); | ||
}; | ||
for (var i = 1; i < ppts.length - 2; i++) { | ||
var c = (ppts[i].x + ppts[i + 1].x) / 2; | ||
var d = (ppts[i].y + ppts[i + 1].y) / 2; | ||
ctxTmp.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d); | ||
} | ||
var copyTmpImage = function() { | ||
if (options.undo) { | ||
scope.$apply(function() { | ||
undoCache.push(ctx.getImageData(0, 0, canvasTmp.width, canvasTmp.height)); | ||
if (angular.isNumber(options.undo) && options.undo > 0) { | ||
undoCache = undoCache.slice(-1 * options.undo); | ||
} | ||
}); | ||
} | ||
canvasTmp.removeEventListener(PAINT_MOVE, paint, false); | ||
ctx.drawImage(canvasTmp, 0, 0); | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
ppts = []; | ||
}; | ||
// For the last 2 points | ||
ctxTmp.quadraticCurveTo( | ||
ppts[i].x, | ||
ppts[i].y, | ||
ppts[i + 1].x, | ||
ppts[i + 1].y | ||
); | ||
ctxTmp.stroke(); | ||
}; | ||
var startTmpImage = function(e) { | ||
e.preventDefault(); | ||
canvasTmp.addEventListener(PAINT_MOVE, paint, false); | ||
var copyTmpImage = function(){ | ||
if(options.undo){ | ||
scope.$apply(function(){ | ||
undoCache.push(ctx.getImageData(0, 0, canvasTmp.width, canvasTmp.height)); | ||
if(angular.isNumber(options.undo) && options.undo > 0){ | ||
undoCache = undoCache.slice(-1 * options.undo); | ||
} | ||
}); | ||
} | ||
canvasTmp.removeEventListener(PAINT_MOVE, paint, false); | ||
ctx.drawImage(canvasTmp, 0, 0); | ||
ctxTmp.clearRect(0, 0, canvasTmp.width, canvasTmp.height); | ||
ppts = []; | ||
}; | ||
setPointFromEvent(point, e); | ||
ppts.push({ | ||
x: point.x, | ||
y: point.y | ||
}); | ||
ppts.push({ | ||
x: point.x, | ||
y: point.y | ||
}); | ||
var startTmpImage = function(e){ | ||
e.preventDefault(); | ||
canvasTmp.addEventListener(PAINT_MOVE, paint, false); | ||
paint(); | ||
}; | ||
setPointFromEvent(point, e); | ||
ppts.push({x: point.x, y: point.y}); | ||
ppts.push({x: point.x, y: point.y}); | ||
var initListeners = function() { | ||
canvasTmp.addEventListener(PAINT_START, startTmpImage, false); | ||
canvasTmp.addEventListener(PAINT_END, copyTmpImage, false); | ||
paint(); | ||
}; | ||
if (!isTouch) { | ||
var MOUSE_DOWN; | ||
var initListeners = function(){ | ||
canvasTmp.addEventListener(PAINT_START, startTmpImage, false); | ||
canvasTmp.addEventListener(PAINT_END, copyTmpImage, false); | ||
document.body.addEventListener('mousedown', mousedown); | ||
document.body.addEventListener('mouseup', mouseup); | ||
if(!isTouch){ | ||
canvasTmp.addEventListener('mouseenter', function(e){ | ||
// If the mouse is down when it enters the canvas, start a path | ||
if(e.which === 1){ | ||
startTmpImage(e); | ||
} | ||
}, false); | ||
canvasTmp.addEventListener('mouseleave', function(e){ | ||
// If the mouse is down when it leaves the canvas, end the path | ||
if(e.which === 1){ | ||
copyTmpImage(e); | ||
} | ||
}, false); | ||
} | ||
}; | ||
initListeners(); | ||
scope.$on('$destroy', removeEventListeners); | ||
canvasTmp.addEventListener('mouseenter', mouseenter); | ||
canvasTmp.addEventListener('mouseleave', mouseleave); | ||
} | ||
function mousedown() { | ||
MOUSE_DOWN = true; | ||
} | ||
var undo = function(version){ | ||
if(undoCache.length > 0){ | ||
ctx.putImageData(undoCache[version], 0, 0); | ||
undoCache = undoCache.slice(0,version); | ||
} | ||
}; | ||
function mouseup() { | ||
MOUSE_DOWN = false; | ||
} | ||
} | ||
}; | ||
}); | ||
function removeEventListeners() { | ||
document.body.removeEventListener('mousedown', mousedown); | ||
document.body.removeEventListener('mouseup', mouseup); | ||
} | ||
function mouseenter(e) { | ||
// If the mouse is down when it enters the canvas, start a path | ||
if (MOUSE_DOWN) { | ||
startTmpImage(e); | ||
} | ||
} | ||
function mouseleave(e) { | ||
// If the mouse is down when it leaves the canvas, end the path | ||
if (MOUSE_DOWN) { | ||
copyTmpImage(e); | ||
} | ||
} | ||
}; | ||
var undo = function(version) { | ||
if (undoCache.length > 0) { | ||
ctx.putImageData(undoCache[version], 0, 0); | ||
undoCache = undoCache.slice(0, version); | ||
} | ||
}; | ||
initListeners(); | ||
} | ||
}; | ||
}); |
'use strict'; | ||
angular.module('pw.canvas-painter') | ||
.directive('pwColorSelector', function () { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
colorList: '=pwColorSelector', | ||
selectedColor: '=color' | ||
}, | ||
templateUrl: '../templates/color-selector.html', | ||
link: function(scope){ | ||
scope.setColor = function(col){ | ||
scope.selectedColor = col; | ||
}; | ||
} | ||
}; | ||
}); | ||
.directive('pwColorSelector', function () { | ||
return { | ||
restrict: 'AE', | ||
scope: { | ||
colorList: '=pwColorSelector', | ||
selectedColor: '=color' | ||
}, | ||
templateUrl: '../templates/color-selector.html', | ||
link: function(scope){ | ||
scope.setColor = function(col){ | ||
scope.selectedColor = col; | ||
}; | ||
} | ||
}; | ||
}); |
{ | ||
"name": "angular-canvas-painter", | ||
"version": "0.5.2", | ||
"version": "0.5.3", | ||
"description": "Angular.js directive to paint on a canvas on desktop or touch devices", | ||
@@ -5,0 +5,0 @@ "main": "dist/angular-canvas-painter.min.js", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36108
659