UNPKG

angular-cropper

Version:

A simple image cropper angular.js (1.x) directive

244 lines (187 loc) 6.07 kB
angular.module('tw.directives.cropper', ['tw.services.fileReader']); angular.module('tw.directives.cropper').directive('twCropper', ['$parse', '$window', '$document', 'twFileReader', function($parse, $window, $document, twFileReader) { var document = $document[0], Math = $window.Math; return { restrict: 'A', controller: ['$scope', '$attrs', '$element', function($scope, $attrs, $element) { var canvas = $element[0]; // If twCropper attribute is provided if ($attrs.twCropper) { // Publish this controller to the scope via the expression $parse($attrs.twCropper).assign($scope, this); } this.toDataURL = function toDataURL() { return canvas.toDataURL(); }; }], link: function(scope, el, attrs) { if (angular.lowercase(el[0].nodeName) !== 'canvas') { return; } var canvas = el[0]; var ctx = canvas.getContext('2d'); var img = new Image(); var x, y, scale, maxScale, minScale; var draw = function draw() { var sx = x, sy = y, sWidth = canvas.width * scale, sHeight = canvas.height * scale, dx = 0, dy = 0, dWidth = canvas.width, dHeight = canvas.height; ctx.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); }; var zoom = function zoom(dScale) { var s = scale; scale += dScale; if (scale < minScale) { scale = minScale; } else if (scale > maxScale) { scale = maxScale; } var newWidth = scale * canvas.width; var newHeight = scale * canvas.height; var oldWidth = s * canvas.width; var oldHeight = s * canvas.height; var dWidth = newWidth - oldWidth; var dHeight = newHeight - oldHeight; x -= dWidth / 2; y -= dHeight / 2; if (x < 0) { x = 0; } else { if (x + newWidth > img.width) { x = img.width - newWidth; } } if (y < 0) { y = 0; } else { if (y + newHeight > img.height) { y = img.height - newHeight; } } }; scope.$watch(attrs.source, function(newVal) { if (!newVal) { ctx.clearRect(0, 0, canvas.width, canvas.height); return; } twFileReader.readAsDataURL(newVal).then(function(dataURL) { img.onload = function() { x = 0; y = 0; scale = minScale = 1; if (img.width > img.height) { maxScale = img.height / canvas.height; } else { maxScale = img.width / canvas.width; } if (img.height < canvas.height) { scale = minScale = maxScale; } if (img.width < canvas.width) { scale = minScale = maxScale; } draw(); }; img.src = dataURL; }); }); var sx, sy; var move = function move(newX, newY) { x += (sx - newX) * scale; y += (sy - newY) * scale; if (x < 0) { x = 0; } else { var scaledWidth = canvas.width * scale; if (x + scaledWidth > img.width) { x = img.width - scaledWidth; } } if (y < 0) { y = 0; } else { var scaledHeight = canvas.height * scale; if (y + scaledHeight > img.height) { y = img.height - scaledHeight; } } draw(); sx = newX; sy = newY; }; var mousemove = function mousemove(e) { move(e.clientX, e.clientY); }; var d = null; var pinch = function pinch(touch1, touch2) { var x1 = touch1.clientX; var y1 = touch1.clientY; var x2 = touch2.clientX; var y2 = touch2.clientY; var newD = Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2)); if (d !== null) { var dx = newD - d; zoom(dx * -.015); draw(); } d = newD; }; var touchmove = function touchmove(e) { // jQuery doesn't copy touches over to its event, so we need to go through originalEvent in that case e = e.originalEvent || e; if (e.touches.length === 1) { move(e.touches[0].clientX, e.touches[0].clientY); } else if (e.touches.length === 2) { pinch(e.touches[0], e.touches[1]); } }; var start = function(x, y) { if (!img.src) { return; } sx = x; sy = y; $document.on('mousemove', mousemove); $document.on('touchmove', touchmove); }; var mousedown = function mousedown(e) { start(e.clientX, e.clientY); }; var touchstart = function touchstart(e) { // jQuery doesn't copy touches over to its event, so we need to go through originalEvent in that case e = e.originalEvent || e; e.preventDefault(); if (e.touches.length === 1) { start(e.touches[0].clientX, e.touches[0].clientY); } }; el.on('mousedown', mousedown); el.on('touchstart', touchstart); var end = function end() { $document.off('mousemove', mousemove); $document.off('touchmove', touchmove); d = null; }; $document.on('mouseup touchend', end); el.on('wheel', function(e) { e.preventDefault(); e = e.originalEvent || e; if (!img.src) { return; } if (e.deltaY < 0) { zoom(-.15); } else { zoom(.15); } draw(); }); } }; }]);