/wp-content/plugins/peepso-core/assets/js/crop.js

https://bitbucket.org/lovetheidea/hop-website · JavaScript · 295 lines · 239 code · 48 blank · 8 comment · 46 complexity · ea37ac8dacac9d8d847ef54a53783b30 MD5 · raw file

  1. (function( $, Hammer, peepso, factory ) {
  2. var mobile = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i;
  3. var IS_DESKTOP = !mobile.test( navigator.userAgent );
  4. var PsCrop = factory( $, Hammer, peepso, IS_DESKTOP );
  5. ps_crop = {};
  6. ps_crop.init = function( config ) {
  7. var elem, inst;
  8. elem = $( config.elem );
  9. inst = elem.data('ps-crop');
  10. if ( inst ) {
  11. inst.destroy();
  12. }
  13. inst = new PsCrop( config );
  14. elem.data('ps-crop', inst );
  15. };
  16. ps_crop.detach = function( elem ) {
  17. var inst;
  18. elem = $( elem );
  19. inst = elem.data('ps-crop');
  20. inst && inst.detach();
  21. };
  22. })( jQuery || $, Hammer, peepso, function( $, Hammer, peepso, IS_DESKTOP ) {
  23. function PsCrop( config ) {
  24. this.$elem = $( config.elem );
  25. this.$wrapper = $('<div class="ps-crop-wrapper" />');
  26. this.$cropper = $('<div class="ps-crop-box" />');
  27. this.$wnd = $( window );
  28. this.change = config.change || $.noop;
  29. this.attach();
  30. this.measurements = this.measure();
  31. this.change( this.getSelection() );
  32. }
  33. PsCrop.prototype.attach = function() {
  34. this.$elem.wrap( this.$wrapper );
  35. this.$cropper.insertAfter( this.$elem );
  36. this.$wrapper = this.$elem.parent();
  37. if ( !this.hammertime ) {
  38. this.hammertime = new Hammer( this.$cropper[0] );
  39. this.hammertime.on('pan panstart panend', $.proxy(function( e ) {
  40. e.srcEvent.stopPropagation();
  41. e.srcEvent.preventDefault();
  42. if ( e.type === 'panstart' ) {
  43. this.disableDesktopEvents();
  44. this.onTouch( e );
  45. } else if ( e.type === 'pan' ) {
  46. this.onDragOrResize( e );
  47. } else {
  48. this.onRelease( e );
  49. this.enableDesktopEvents();
  50. }
  51. }, this ));
  52. }
  53. this.enableDesktopEvents();
  54. };
  55. PsCrop.prototype.detach = function() {
  56. this.$cropper.detach();
  57. if ( this.$elem.parent().is( this.$wrapper ) ) {
  58. this.$elem.unwrap();
  59. }
  60. };
  61. PsCrop.prototype.measure = function() {
  62. var img = this.$elem,
  63. wrp = this.$wrapper[0],
  64. pos = this.$cropper.position();
  65. return {
  66. imageWidth : img.width(),
  67. imageHeight : img.height(),
  68. wrapperTop : wrp.scrollTop,
  69. wrapperLeft : wrp.scrollLeft,
  70. wrapperWidth : this.$wrapper.width(),
  71. wrapperHeight : this.$wrapper.height(),
  72. cropperTop : pos.top + wrp.scrollTop,
  73. cropperLeft : pos.left + wrp.scrollLeft,
  74. cropperWidth : this.$cropper.outerWidth(),
  75. cropperHeight : this.$cropper.outerHeight()
  76. };
  77. };
  78. PsCrop.prototype.getPointerPosition = function( x, y ) {
  79. var offset = this.$cropper.offset();
  80. return {
  81. top: y - offset.top + this.$wnd.scrollTop(),
  82. left: x - offset.left + this.$wnd.scrollLeft()
  83. };
  84. };
  85. PsCrop.prototype.getResizeDirection = function( e ) {
  86. var treshhold = IS_DESKTOP ? 15 : 20,
  87. pos = this.getPointerPosition( e.center.x, e.center.y ),
  88. mea = this.measurements,
  89. dir = '';
  90. if ( pos.top < treshhold ) {
  91. dir += 'n';
  92. } else if ( pos.top > mea.cropperHeight - treshhold ) {
  93. dir += 's';
  94. }
  95. if ( pos.left < treshhold ) {
  96. dir += 'w';
  97. } else if ( pos.left > mea.cropperWidth - treshhold ) {
  98. dir += 'e';
  99. }
  100. return dir;
  101. };
  102. PsCrop.prototype.getSelection = function() {
  103. return {
  104. x: this.measurements.cropperLeft,
  105. y: this.measurements.cropperTop,
  106. width: this.measurements.cropperWidth,
  107. height: this.measurements.cropperHeight
  108. };
  109. };
  110. PsCrop.prototype.onTouch = function( e ) {
  111. this.released = false;
  112. this.measurements = this.measure();
  113. this.direction = this.getResizeDirection( e );
  114. };
  115. PsCrop.prototype.onDragOrResize = _.throttle(function( e ) {
  116. this.direction ? this.onResize( e ) : this.onDrag( e );
  117. }, IS_DESKTOP ? 10 : 100 );
  118. PsCrop.prototype.onDrag = function( e ) {
  119. var mea = this.measurements,
  120. top = e.deltaY,
  121. left = e.deltaX,
  122. value;
  123. // Stop on `panend` event.
  124. if ( this.released ) {
  125. return;
  126. }
  127. // Respect horizontal boundaries.
  128. left = Math.min( left, mea.imageWidth - mea.cropperWidth - mea.cropperLeft );
  129. left = Math.max( left, 0 - mea.cropperLeft );
  130. // Respect vertical boundaries.
  131. top = Math.min( top, mea.imageHeight - mea.cropperHeight - mea.cropperTop );
  132. top = Math.max( top, 0 - mea.cropperTop );
  133. value = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
  134. this.$cropper.css({
  135. webkitTransform: value,
  136. mozTransform: value,
  137. transform: value
  138. });
  139. };
  140. PsCrop.prototype.onResize = function( e ) {
  141. var dir = this.direction,
  142. mea = this.measurements,
  143. css = {};
  144. // Stop on `panend` event.
  145. if ( this.released ) {
  146. return;
  147. }
  148. if ( dir.match( /n/ ) ) {
  149. css.top = 'auto';
  150. css.bottom = mea.wrapperHeight - mea.cropperTop - mea.cropperHeight;
  151. css.height = mea.cropperHeight - e.deltaY;
  152. } else if ( dir.match( /s/ ) ) {
  153. css.bottom = 'auto';
  154. css.top = mea.cropperTop;
  155. css.height = mea.cropperHeight + e.deltaY;
  156. }
  157. if ( dir.match( /e/ ) ) {
  158. css.right = 'auto';
  159. css.left = mea.cropperLeft;
  160. css.width = mea.cropperWidth + e.deltaX;
  161. } else if ( dir.match( /w/ ) ) {
  162. css.left = 'auto';
  163. css.right = mea.wrapperWidth - mea.cropperLeft - mea.cropperWidth;
  164. css.width = mea.cropperWidth - e.deltaX;
  165. }
  166. // Restrict cropper box to 1:1 ratio.
  167. css.width = css.height = Math.max( css.width || 0, css.height || 0, 64 );
  168. // Respect vertical boundaries.
  169. if ( dir.match( /n/ ) ) {
  170. css.height = Math.min( css.height, mea.wrapperHeight - css.bottom );
  171. } else if ( dir.match( /s/ ) ) {
  172. css.height = Math.min( css.height, mea.imageHeight - css.top );
  173. } else if ( this.$cropper[0].style.top !== 'auto' ) {
  174. css.height = Math.min( css.height, mea.imageHeight - parseInt( this.$cropper.css('top') ) );
  175. } else {
  176. css.height = Math.min( css.height, mea.wrapperHeight - parseInt( this.$cropper.css('bottom') ) );
  177. }
  178. // Respect horizontal boundaries.
  179. if ( dir.match( /e/ ) ) {
  180. css.width = Math.min( css.width, mea.imageWidth - css.left );
  181. } else if ( dir.match( /w/ ) ) {
  182. css.width = Math.min( css.width, mea.wrapperWidth - css.right );
  183. } else if ( this.$cropper[0].style.left !== 'auto' ) {
  184. css.width = Math.min( css.width, mea.imageWidth - parseInt( this.$cropper.css('left') ) );
  185. } else {
  186. css.width = Math.min( css.width, mea.wrapperWidth - parseInt( this.$cropper.css('right') ) );
  187. }
  188. // Restrict cropper box to 1:1 ratio.
  189. css.width = css.height = Math.min( css.width, css.height );
  190. this.$cropper.css( css );
  191. };
  192. PsCrop.prototype.onRelease = function( e ) {
  193. var pos = this.$cropper.position(),
  194. mea = this.measurements,
  195. css = {
  196. top: Math.max( pos.top + mea.wrapperTop, 0 ),
  197. left: Math.max( pos.left + mea.wrapperLeft, 0 ),
  198. right: '',
  199. bottom: '',
  200. webkitTransform: '',
  201. mozTransform: '',
  202. transform: ''
  203. };
  204. this.released = true;
  205. this.$cropper.css( css );
  206. this.measurements = this.measure();
  207. this.change( this.getSelection() );
  208. };
  209. PsCrop.prototype.destroy = function() {
  210. this.detach();
  211. this.$elem = null;
  212. this.$wrapper = null;
  213. this.$cropper = null;
  214. this.$wnd = null;
  215. this.hammertime = null;
  216. };
  217. PsCrop.prototype.enableDesktopEvents = function() {
  218. if ( IS_DESKTOP ) {
  219. this.$cropper.on('mousemove.ps-crop', $.proxy( this.onMouseMove, this ));
  220. }
  221. };
  222. PsCrop.prototype.disableDesktopEvents = function() {
  223. if ( IS_DESKTOP ) {
  224. this.$cropper.off('mousemove.ps-crop');
  225. }
  226. };
  227. PsCrop.prototype.onMouseMove = function( e ) {
  228. var parentOffset = $( e.target ).parent().offset(),
  229. relX = e.pageX - parentOffset.left,
  230. relY = e.pageY - parentOffset.top,
  231. treshhold = 15,
  232. cursor = '',
  233. m = this.measure();
  234. if ( relY < m.cropperTop - m.wrapperTop + treshhold ) {
  235. cursor += 'n';
  236. } else if ( relY > m.cropperTop - m.wrapperTop + m.cropperHeight - treshhold ) {
  237. cursor += 's';
  238. }
  239. if ( relX < m.cropperLeft - m.wrapperLeft + treshhold ) {
  240. cursor += 'w';
  241. } else if ( relX > m.cropperLeft - m.wrapperLeft + m.cropperWidth - treshhold ) {
  242. cursor += 'e';
  243. }
  244. this.$cropper.css({ cursor: cursor ? cursor + '-resize' : '' });
  245. };
  246. return PsCrop;
  247. });