crop-host.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. 'use strict';
  2. crop.factory('cropHost', ['$document', 'cropAreaCircle', 'cropAreaSquare', 'cropEXIF', function($document, CropAreaCircle, CropAreaSquare, cropEXIF) {
  3. /* STATIC FUNCTIONS */
  4. // Get Element's Offset
  5. var getElementOffset=function(elem) {
  6. var box = elem.getBoundingClientRect();
  7. var body = document.body;
  8. var docElem = document.documentElement;
  9. var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
  10. var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
  11. var clientTop = docElem.clientTop || body.clientTop || 0;
  12. var clientLeft = docElem.clientLeft || body.clientLeft || 0;
  13. var top = box.top + scrollTop - clientTop;
  14. var left = box.left + scrollLeft - clientLeft;
  15. return { top: Math.round(top), left: Math.round(left) };
  16. };
  17. return function(elCanvas, opts, events){
  18. /* PRIVATE VARIABLES */
  19. // Object Pointers
  20. var ctx=null,
  21. image=null,
  22. theArea=null;
  23. // Dimensions
  24. var minCanvasDims=[100,100],
  25. maxCanvasDims=[300,300];
  26. // Result Image size
  27. var resImgSize=200;
  28. // Result Image type
  29. var resImgFormat='image/png';
  30. // Result Image quality
  31. var resImgQuality=null;
  32. /* PRIVATE FUNCTIONS */
  33. // Draw Scene
  34. function drawScene() {
  35. // clear canvas
  36. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  37. if(image!==null) {
  38. // draw source image
  39. ctx.drawImage(image, 0, 0, ctx.canvas.width, ctx.canvas.height);
  40. ctx.save();
  41. // and make it darker
  42. ctx.fillStyle = 'rgba(0, 0, 0, 0.65)';
  43. ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  44. ctx.restore();
  45. // draw Area
  46. theArea.draw();
  47. }
  48. }
  49. // Resets CropHost
  50. var resetCropHost=function() {
  51. if(image!==null) {
  52. theArea.setImage(image);
  53. var imageDims=[image.width, image.height],
  54. imageRatio=image.width/image.height,
  55. canvasDims=imageDims;
  56. if(canvasDims[0]>maxCanvasDims[0]) {
  57. canvasDims[0]=maxCanvasDims[0];
  58. canvasDims[1]=canvasDims[0]/imageRatio;
  59. } else if(canvasDims[0]<minCanvasDims[0]) {
  60. canvasDims[0]=minCanvasDims[0];
  61. canvasDims[1]=canvasDims[0]/imageRatio;
  62. }
  63. if(canvasDims[1]>maxCanvasDims[1]) {
  64. canvasDims[1]=maxCanvasDims[1];
  65. canvasDims[0]=canvasDims[1]*imageRatio;
  66. } else if(canvasDims[1]<minCanvasDims[1]) {
  67. canvasDims[1]=minCanvasDims[1];
  68. canvasDims[0]=canvasDims[1]*imageRatio;
  69. }
  70. elCanvas.prop('width',canvasDims[0]).prop('height',canvasDims[1]).css({'margin-left': -canvasDims[0]/2+'px', 'margin-top': -canvasDims[1]/2+'px'});
  71. theArea.setX(ctx.canvas.width/2);
  72. theArea.setY(ctx.canvas.height/2);
  73. theArea.setSize(Math.min(200, ctx.canvas.width/2, ctx.canvas.height/2));
  74. } else {
  75. elCanvas.prop('width',0).prop('height',0).css({'margin-top': 0});
  76. }
  77. drawScene();
  78. };
  79. /**
  80. * Returns event.changedTouches directly if event is a TouchEvent.
  81. * If event is a jQuery event, return changedTouches of event.originalEvent
  82. */
  83. var getChangedTouches=function(event){
  84. if(angular.isDefined(event.changedTouches)){
  85. return event.changedTouches;
  86. }else{
  87. return event.originalEvent.changedTouches;
  88. }
  89. };
  90. var onMouseMove=function(e) {
  91. if(image!==null) {
  92. var offset=getElementOffset(ctx.canvas),
  93. pageX, pageY;
  94. if(e.type === 'touchmove') {
  95. pageX=getChangedTouches(e)[0].pageX;
  96. pageY=getChangedTouches(e)[0].pageY;
  97. } else {
  98. pageX=e.pageX;
  99. pageY=e.pageY;
  100. }
  101. theArea.processMouseMove(pageX-offset.left, pageY-offset.top);
  102. drawScene();
  103. }
  104. };
  105. var onMouseDown=function(e) {
  106. e.preventDefault();
  107. e.stopPropagation();
  108. if(image!==null) {
  109. var offset=getElementOffset(ctx.canvas),
  110. pageX, pageY;
  111. if(e.type === 'touchstart') {
  112. pageX=getChangedTouches(e)[0].pageX;
  113. pageY=getChangedTouches(e)[0].pageY;
  114. } else {
  115. pageX=e.pageX;
  116. pageY=e.pageY;
  117. }
  118. theArea.processMouseDown(pageX-offset.left, pageY-offset.top);
  119. drawScene();
  120. }
  121. };
  122. var onMouseUp=function(e) {
  123. if(image!==null) {
  124. var offset=getElementOffset(ctx.canvas),
  125. pageX, pageY;
  126. if(e.type === 'touchend') {
  127. pageX=getChangedTouches(e)[0].pageX;
  128. pageY=getChangedTouches(e)[0].pageY;
  129. } else {
  130. pageX=e.pageX;
  131. pageY=e.pageY;
  132. }
  133. theArea.processMouseUp(pageX-offset.left, pageY-offset.top);
  134. drawScene();
  135. }
  136. };
  137. this.getResultImageDataURI=function() {
  138. var temp_ctx, temp_canvas;
  139. temp_canvas = angular.element('<canvas></canvas>')[0];
  140. temp_ctx = temp_canvas.getContext('2d');
  141. temp_canvas.width = resImgSize;
  142. temp_canvas.height = resImgSize;
  143. if(image!==null){
  144. temp_ctx.drawImage(image, (theArea.getX()-theArea.getSize()/2)*(image.width/ctx.canvas.width), (theArea.getY()-theArea.getSize()/2)*(image.height/ctx.canvas.height), theArea.getSize()*(image.width/ctx.canvas.width), theArea.getSize()*(image.height/ctx.canvas.height), 0, 0, resImgSize, resImgSize);
  145. }
  146. if (resImgQuality!==null ){
  147. return temp_canvas.toDataURL(resImgFormat, resImgQuality);
  148. }
  149. return temp_canvas.toDataURL(resImgFormat);
  150. };
  151. this.setNewImageSource=function(imageSource) {
  152. image=null;
  153. resetCropHost();
  154. events.trigger('image-updated');
  155. if(!!imageSource) {
  156. var newImage = new Image();
  157. if(imageSource.substring(0,4).toLowerCase()==='http') {
  158. newImage.crossOrigin = 'anonymous';
  159. }
  160. newImage.onload = function(){
  161. events.trigger('load-done');
  162. cropEXIF.getData(newImage,function(){
  163. var orientation=cropEXIF.getTag(newImage,'Orientation');
  164. if([3,6,8].indexOf(orientation)>-1) {
  165. var canvas = document.createElement("canvas"),
  166. ctx=canvas.getContext("2d"),
  167. cw = newImage.width, ch = newImage.height, cx = 0, cy = 0, deg=0;
  168. switch(orientation) {
  169. case 3:
  170. cx=-newImage.width;
  171. cy=-newImage.height;
  172. deg=180;
  173. break;
  174. case 6:
  175. cw = newImage.height;
  176. ch = newImage.width;
  177. cy=-newImage.height;
  178. deg=90;
  179. break;
  180. case 8:
  181. cw = newImage.height;
  182. ch = newImage.width;
  183. cx=-newImage.width;
  184. deg=270;
  185. break;
  186. }
  187. canvas.width = cw;
  188. canvas.height = ch;
  189. ctx.rotate(deg*Math.PI/180);
  190. ctx.drawImage(newImage, cx, cy);
  191. image=new Image();
  192. image.src = canvas.toDataURL("image/png");
  193. } else {
  194. image=newImage;
  195. }
  196. resetCropHost();
  197. events.trigger('image-updated');
  198. });
  199. };
  200. newImage.onerror=function() {
  201. events.trigger('load-error');
  202. };
  203. events.trigger('load-start');
  204. newImage.src=imageSource;
  205. }
  206. };
  207. this.setMaxDimensions=function(width, height) {
  208. maxCanvasDims=[width,height];
  209. if(image!==null) {
  210. var curWidth=ctx.canvas.width,
  211. curHeight=ctx.canvas.height;
  212. var imageDims=[image.width, image.height],
  213. imageRatio=image.width/image.height,
  214. canvasDims=imageDims;
  215. if(canvasDims[0]>maxCanvasDims[0]) {
  216. canvasDims[0]=maxCanvasDims[0];
  217. canvasDims[1]=canvasDims[0]/imageRatio;
  218. } else if(canvasDims[0]<minCanvasDims[0]) {
  219. canvasDims[0]=minCanvasDims[0];
  220. canvasDims[1]=canvasDims[0]/imageRatio;
  221. }
  222. if(canvasDims[1]>maxCanvasDims[1]) {
  223. canvasDims[1]=maxCanvasDims[1];
  224. canvasDims[0]=canvasDims[1]*imageRatio;
  225. } else if(canvasDims[1]<minCanvasDims[1]) {
  226. canvasDims[1]=minCanvasDims[1];
  227. canvasDims[0]=canvasDims[1]*imageRatio;
  228. }
  229. elCanvas.prop('width',canvasDims[0]).prop('height',canvasDims[1]).css({'margin-left': -canvasDims[0]/2+'px', 'margin-top': -canvasDims[1]/2+'px'});
  230. var ratioNewCurWidth=ctx.canvas.width/curWidth,
  231. ratioNewCurHeight=ctx.canvas.height/curHeight,
  232. ratioMin=Math.min(ratioNewCurWidth, ratioNewCurHeight);
  233. theArea.setX(theArea.getX()*ratioNewCurWidth);
  234. theArea.setY(theArea.getY()*ratioNewCurHeight);
  235. theArea.setSize(theArea.getSize()*ratioMin);
  236. } else {
  237. elCanvas.prop('width',0).prop('height',0).css({'margin-top': 0});
  238. }
  239. drawScene();
  240. };
  241. this.setAreaMinSize=function(size) {
  242. size=parseInt(size,10);
  243. if(!isNaN(size)) {
  244. theArea.setMinSize(size);
  245. drawScene();
  246. }
  247. };
  248. this.setResultImageSize=function(size) {
  249. size=parseInt(size,10);
  250. if(!isNaN(size)) {
  251. resImgSize=size;
  252. }
  253. };
  254. this.setResultImageFormat=function(format) {
  255. resImgFormat = format;
  256. };
  257. this.setResultImageQuality=function(quality){
  258. quality = parseFloat(quality);
  259. if (!isNaN(quality) && quality>=0 && quality<=1){
  260. resImgQuality = quality;
  261. }
  262. };
  263. this.setAreaType=function(type) {
  264. var curSize=theArea.getSize(),
  265. curMinSize=theArea.getMinSize(),
  266. curX=theArea.getX(),
  267. curY=theArea.getY();
  268. var AreaClass=CropAreaCircle;
  269. if(type==='square') {
  270. AreaClass=CropAreaSquare;
  271. }
  272. theArea = new AreaClass(ctx, events);
  273. theArea.setMinSize(curMinSize);
  274. theArea.setSize(curSize);
  275. theArea.setX(curX);
  276. theArea.setY(curY);
  277. // resetCropHost();
  278. if(image!==null) {
  279. theArea.setImage(image);
  280. }
  281. drawScene();
  282. };
  283. /* Life Cycle begins */
  284. // Init Context var
  285. ctx = elCanvas[0].getContext('2d');
  286. // Init CropArea
  287. theArea = new CropAreaCircle(ctx, events);
  288. // Init Mouse Event Listeners
  289. $document.on('mousemove',onMouseMove);
  290. elCanvas.on('mousedown',onMouseDown);
  291. $document.on('mouseup',onMouseUp);
  292. // Init Touch Event Listeners
  293. $document.on('touchmove',onMouseMove);
  294. elCanvas.on('touchstart',onMouseDown);
  295. $document.on('touchend',onMouseUp);
  296. // CropHost Destructor
  297. this.destroy=function() {
  298. $document.off('mousemove',onMouseMove);
  299. elCanvas.off('mousedown',onMouseDown);
  300. $document.off('mouseup',onMouseMove);
  301. $document.off('touchmove',onMouseMove);
  302. elCanvas.off('touchstart',onMouseDown);
  303. $document.off('touchend',onMouseMove);
  304. elCanvas.remove();
  305. };
  306. };
  307. }]);