Няма описание

um-crop.js 43KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573
  1. (function (factory) {
  2. if (typeof define === "function" && define.amd) {
  3. // AMD. Register as anonymous module.
  4. define(["jquery"], factory);
  5. } else if (typeof exports === "object") {
  6. // Node / CommonJS
  7. factory(require("jquery"));
  8. } else {
  9. // Browser globals.
  10. factory(jQuery);
  11. }
  12. })(function ($) {
  13. "use strict";
  14. var $window = $(window),
  15. $document = $(document),
  16. location = window.location,
  17. // Constants
  18. TRUE = true,
  19. FALSE = false,
  20. NULL = null,
  21. NAN = NaN,
  22. INFINITY = Infinity,
  23. STRING_UNDEFINED = "undefined",
  24. STRING_DIRECTIVE = "directive",
  25. CROPPER_NAMESPACE = ".cropper",
  26. // RegExps
  27. REGEXP_DIRECTIVES = /^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/,
  28. REGEXP_OPTIONS = /^(x|y|width|height)$/,
  29. REGEXP_PROPERTIES = /^(naturalWidth|naturalHeight|width|height|aspectRatio|ratio|rotate)$/,
  30. // Classes
  31. CLASS_MODAL = "cropper-modal",
  32. CLASS_HIDDEN = "cropper-hidden",
  33. CLASS_INVISIBLE = "cropper-invisible",
  34. CLASS_MOVE = "cropper-move",
  35. CLASS_CROP = "cropper-crop",
  36. CLASS_DISABLED = "cropper-disabled",
  37. // Events
  38. EVENT_MOUSE_DOWN = "mousedown touchstart",
  39. EVENT_MOUSE_MOVE = "mousemove touchmove",
  40. EVENT_MOUSE_UP = "mouseup mouseleave touchend touchleave touchcancel",
  41. EVENT_WHEEL = "wheel mousewheel DOMMouseScroll",
  42. EVENT_RESIZE = "resize" + CROPPER_NAMESPACE, // Bind to window with namespace
  43. EVENT_DBLCLICK = "dblclick",
  44. EVENT_BUILD = "build" + CROPPER_NAMESPACE,
  45. EVENT_BUILT = "built" + CROPPER_NAMESPACE,
  46. EVENT_DRAG_START = "dragstart" + CROPPER_NAMESPACE,
  47. EVENT_DRAG_MOVE = "dragmove" + CROPPER_NAMESPACE,
  48. EVENT_DRAG_END = "dragend" + CROPPER_NAMESPACE,
  49. // Functions
  50. isNumber = function (n) {
  51. return typeof n === "number";
  52. },
  53. toArray = function (obj, offset) {
  54. var args = [];
  55. if (typeof offset === "number") { // It's necessary for IE8
  56. args.push(offset);
  57. }
  58. return args.slice.apply(obj, args);
  59. },
  60. // Custom proxy to avoid jQuery's guid
  61. proxy = function (fn, context) {
  62. var args = toArray(arguments, 2);
  63. return function () {
  64. return fn.apply(context, args.concat(toArray(arguments)));
  65. };
  66. },
  67. // Constructor
  68. Cropper = function (element, options) {
  69. this.element = element;
  70. this.$element = $(element);
  71. this.defaults = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) ? options : {});
  72. this.$original = NULL;
  73. this.ready = FALSE;
  74. this.built = FALSE;
  75. this.cropped = FALSE;
  76. this.rotated = FALSE;
  77. this.disabled = FALSE;
  78. this.replaced = FALSE;
  79. this.init();
  80. },
  81. // Others
  82. sqrt = Math.sqrt,
  83. min = Math.min,
  84. max = Math.max,
  85. abs = Math.abs,
  86. sin = Math.sin,
  87. cos = Math.cos,
  88. num = parseFloat;
  89. Cropper.prototype = {
  90. constructor: Cropper,
  91. support: {
  92. canvas: $.isFunction($("<canvas>")[0].getContext)
  93. },
  94. init: function () {
  95. var defaults = this.defaults;
  96. $.each(defaults, function (i, n) {
  97. switch (i) {
  98. case "aspectRatio":
  99. defaults[i] = abs(num(n)) || NAN; // 0 -> NaN
  100. break;
  101. case "autoCropArea":
  102. defaults[i] = abs(num(n)) || 0.8; // 0 | NaN -> 0.8
  103. break;
  104. case "minWidth":
  105. case "minHeight":
  106. defaults[i] = abs(num(n)) || 0; // NaN -> 0
  107. break;
  108. case "maxWidth":
  109. case "maxHeight":
  110. defaults[i] = abs(num(n)) || INFINITY; // 0 | NaN -> Infinity
  111. break;
  112. // No default
  113. }
  114. });
  115. // Set default image data
  116. this.image = {
  117. rotate: 0
  118. };
  119. this.load();
  120. },
  121. load: function () {
  122. var _this = this,
  123. $this = this.$element,
  124. element = this.element,
  125. image = this.image,
  126. crossOrigin = "",
  127. $clone,
  128. url;
  129. if ($this.is("img")) {
  130. url = $this.prop("src");
  131. } else if ($this.is("canvas") && this.support.canvas) {
  132. url = element.toDataURL();
  133. }
  134. if (!url) {
  135. return;
  136. }
  137. // Reset image rotate degree
  138. if (this.replaced) {
  139. image.rotate = 0;
  140. }
  141. if (this.defaults.checkImageOrigin) {
  142. if ($this.prop("crossOrigin") || this.isCrossOriginURL(url)) {
  143. crossOrigin = " crossOrigin";
  144. }
  145. }
  146. this.$clone = ($clone = $("<img" + crossOrigin + ' src="' + url + '">'));
  147. $clone.one("load", function () {
  148. image.naturalWidth = this.naturalWidth || $clone.width();
  149. image.naturalHeight = this.naturalHeight || $clone.height();
  150. image.aspectRatio = image.naturalWidth / image.naturalHeight;
  151. _this.url = url;
  152. _this.ready = TRUE;
  153. _this.build();
  154. });
  155. // Hide and prepend the clone iamge to the document body (Don't append to).
  156. $clone.addClass(CLASS_INVISIBLE).prependTo("body");
  157. },
  158. isCrossOriginURL: function (url) {
  159. var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);
  160. if ((parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port))) {
  161. return TRUE;
  162. }
  163. return FALSE;
  164. },
  165. build: function () {
  166. var $this = this.$element,
  167. defaults = this.defaults,
  168. buildEvent,
  169. $cropper;
  170. if (!this.ready) {
  171. return;
  172. }
  173. if (this.built) {
  174. this.unbuild();
  175. }
  176. $this.one(EVENT_BUILD, defaults.build); // Only trigger once
  177. buildEvent = $.Event(EVENT_BUILD);
  178. $this.trigger(buildEvent);
  179. if (buildEvent.isDefaultPrevented()) {
  180. return;
  181. }
  182. // Create cropper elements
  183. this.$cropper = ($cropper = $(Cropper.TEMPLATE));
  184. // Hide the original image
  185. $this.addClass(CLASS_HIDDEN);
  186. // Show and prepend the clone iamge to the cropper
  187. this.$clone.removeClass(CLASS_INVISIBLE).prependTo($cropper);
  188. // Save original image for rotation
  189. if (!this.rotated) {
  190. this.$original = this.$clone.clone();
  191. // Append the image to document to avoid "NS_ERROR_NOT_AVAILABLE" error on Firefox when call the "drawImage" method.
  192. this.$original.addClass(CLASS_HIDDEN).prependTo(this.$cropper);
  193. this.originalImage = $.extend({}, this.image);
  194. }
  195. this.$container = $this.parent();
  196. this.$container.append($cropper);
  197. this.$canvas = $cropper.find(".cropper-canvas");
  198. this.$dragger = $cropper.find(".cropper-dragger");
  199. this.$viewer = $cropper.find(".cropper-viewer");
  200. defaults.autoCrop ? (this.cropped = TRUE) : this.$dragger.addClass(CLASS_HIDDEN);
  201. defaults.dragCrop && this.setDragMode("crop");
  202. defaults.modal && this.$canvas.addClass(CLASS_MODAL);
  203. !defaults.dashed && this.$dragger.find(".cropper-dashed").addClass(CLASS_HIDDEN);
  204. !defaults.movable && this.$dragger.find(".cropper-face").data(STRING_DIRECTIVE, "move");
  205. !defaults.resizable && this.$dragger.find(".cropper-line, .cropper-point").addClass(CLASS_HIDDEN);
  206. this.addListeners();
  207. this.initPreview();
  208. this.built = TRUE; // Set `true` before update
  209. this.update();
  210. this.replaced = FALSE; // Reset to `false` after update
  211. $this.one(EVENT_BUILT, defaults.built); // Only trigger once
  212. $this.trigger(EVENT_BUILT);
  213. },
  214. unbuild: function () {
  215. if (!this.built) {
  216. return;
  217. }
  218. this.built = FALSE;
  219. this.removeListeners();
  220. this.$preview.empty();
  221. this.$preview = NULL;
  222. this.$dragger = NULL;
  223. this.$canvas = NULL;
  224. this.$container = NULL;
  225. this.$cropper.remove();
  226. this.$cropper = NULL;
  227. },
  228. update: function (data) {
  229. this.initContainer();
  230. this.initCropper();
  231. this.initImage();
  232. this.initDragger();
  233. if (data) {
  234. this.setData(data, TRUE);
  235. this.setDragMode("crop");
  236. } else {
  237. this.setData(this.defaults.data);
  238. }
  239. },
  240. resize: function () {
  241. clearTimeout(this.resizing);
  242. this.resizing = setTimeout($.proxy(this.update, this, this.getData()), 200);
  243. },
  244. preview: function () {
  245. var image = this.image,
  246. dragger = this.dragger,
  247. width = image.width,
  248. height = image.height,
  249. left = dragger.left - image.left,
  250. top = dragger.top - image.top;
  251. this.$viewer.find("img").css({
  252. width: width,
  253. height: height,
  254. marginLeft: -left,
  255. marginTop: -top
  256. });
  257. this.$preview.each(function () {
  258. var $this = $(this),
  259. ratio = $this.width() / dragger.width;
  260. $this.find("img").css({
  261. width: width * ratio,
  262. height: height * ratio,
  263. marginLeft: -left * ratio,
  264. marginTop: -top * ratio
  265. });
  266. });
  267. },
  268. addListeners: function () {
  269. var defaults = this.defaults;
  270. this.$element.on(EVENT_DRAG_START, defaults.dragstart).on(EVENT_DRAG_MOVE, defaults.dragmove).on(EVENT_DRAG_END, defaults.dragend);
  271. this.$cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.dragstart, this)).on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
  272. if (defaults.zoomable) {
  273. this.$cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
  274. }
  275. if (defaults.multiple) {
  276. this.$cropper.on(EVENT_MOUSE_MOVE, $.proxy(this.dragmove, this)).on(EVENT_MOUSE_UP, $.proxy(this.dragend, this));
  277. } else {
  278. $document.on(EVENT_MOUSE_MOVE, (this._dragmove = proxy(this.dragmove, this))).on(EVENT_MOUSE_UP, (this._dragend = proxy(this.dragend, this)));
  279. }
  280. $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
  281. },
  282. removeListeners: function () {
  283. var defaults = this.defaults;
  284. this.$element.off(EVENT_DRAG_START, defaults.dragstart).off(EVENT_DRAG_MOVE, defaults.dragmove).off(EVENT_DRAG_END, defaults.dragend);
  285. this.$cropper.off(EVENT_MOUSE_DOWN, this.dragstart).off(EVENT_DBLCLICK, this.dblclick);
  286. if (defaults.zoomable) {
  287. this.$cropper.off(EVENT_WHEEL, this.wheel);
  288. }
  289. if (defaults.multiple) {
  290. this.$cropper.off(EVENT_MOUSE_MOVE, this.dragmove).off(EVENT_MOUSE_UP, this.dragend);
  291. } else {
  292. $document.off(EVENT_MOUSE_MOVE, this._dragmove).off(EVENT_MOUSE_UP, this._dragend);
  293. }
  294. $window.off(EVENT_RESIZE, this._resize);
  295. },
  296. initPreview: function () {
  297. var img = '<img src="' + this.url + '">';
  298. this.$preview = $(this.defaults.preview);
  299. this.$viewer.html(img);
  300. this.$preview.html(img).find("img").css("cssText", "min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;");
  301. },
  302. initContainer: function () {
  303. var $container = this.$container;
  304. if($container !== NULL){
  305. this.container = {
  306. width: max($container.width(), 300),
  307. height: max($container.height(), 150)
  308. };
  309. }
  310. },
  311. initCropper: function () {
  312. var container = this.container,
  313. image = this.image,
  314. cropper;
  315. if (((image.naturalWidth * container.height / image.naturalHeight) - container.width) >= 0) {
  316. cropper = {
  317. width: container.width,
  318. height: container.width / image.aspectRatio,
  319. left: 0
  320. };
  321. cropper.top = (container.height - cropper.height) / 2;
  322. } else {
  323. cropper = {
  324. width: container.height * image.aspectRatio,
  325. height: container.height,
  326. top: 0
  327. };
  328. cropper.left = (container.width - cropper.width) / 2;
  329. }
  330. if ( this.$cropper ) {
  331. this.$cropper.css({
  332. width: cropper.width,
  333. height: cropper.height,
  334. left: cropper.left,
  335. top: cropper.top
  336. });
  337. }
  338. this.cropper = cropper;
  339. },
  340. initImage: function () {
  341. var image = this.image,
  342. cropper = this.cropper,
  343. defaultImage = {
  344. _width: cropper.width,
  345. _height: cropper.height,
  346. width: cropper.width,
  347. height: cropper.height,
  348. left: 0,
  349. top: 0,
  350. ratio: cropper.width / image.naturalWidth
  351. };
  352. this.defaultImage = $.extend({}, image, defaultImage);
  353. if (image._width !== cropper.width || image._height !== cropper.height) {
  354. $.extend(image, defaultImage);
  355. } else {
  356. image = $.extend({}, defaultImage, image);
  357. // Reset image ratio
  358. if (this.replaced) {
  359. image.ratio = defaultImage.ratio;
  360. }
  361. }
  362. this.image = image;
  363. this.renderImage();
  364. },
  365. renderImage: function (mode) {
  366. var image = this.image;
  367. if (mode === "zoom") {
  368. image.left -= (image.width - image.oldWidth) / 2;
  369. image.top -= (image.height - image.oldHeight) / 2;
  370. }
  371. image.left = min(max(image.left, image._width - image.width), 0);
  372. image.top = min(max(image.top, image._height - image.height), 0);
  373. this.$clone.css({
  374. width: image.width,
  375. height: image.height,
  376. marginLeft: image.left,
  377. marginTop: image.top
  378. });
  379. if (mode) {
  380. this.defaults.done(this.getData());
  381. this.preview();
  382. }
  383. },
  384. initDragger: function () {
  385. var defaults = this.defaults,
  386. cropper = this.cropper,
  387. // If not set, use the original aspect ratio of the image.
  388. aspectRatio = defaults.aspectRatio || this.image.aspectRatio,
  389. ratio = this.image.ratio,
  390. dragger;
  391. if (((cropper.height * aspectRatio) - cropper.width) >= 0) {
  392. dragger = {
  393. height: cropper.width / aspectRatio,
  394. width: cropper.width,
  395. left: 0,
  396. top: (cropper.height - (cropper.width / aspectRatio)) / 2,
  397. maxWidth: cropper.width,
  398. maxHeight: cropper.width / aspectRatio
  399. };
  400. } else {
  401. dragger = {
  402. height: cropper.height,
  403. width: cropper.height * aspectRatio,
  404. left: (cropper.width - (cropper.height * aspectRatio)) / 2,
  405. top: 0,
  406. maxWidth: cropper.height * aspectRatio,
  407. maxHeight: cropper.height
  408. };
  409. }
  410. dragger.minWidth = 0;
  411. dragger.minHeight = 0;
  412. if (defaults.aspectRatio) {
  413. if (isFinite(defaults.maxWidth)) {
  414. dragger.maxWidth = min(dragger.maxWidth, defaults.maxWidth * ratio);
  415. dragger.maxHeight = dragger.maxWidth / aspectRatio;
  416. } else if (isFinite(defaults.maxHeight)) {
  417. dragger.maxHeight = min(dragger.maxHeight, defaults.maxHeight * ratio);
  418. dragger.maxWidth = dragger.maxHeight * aspectRatio;
  419. }
  420. if (defaults.minWidth > 0) {
  421. dragger.minWidth = max(0, defaults.minWidth * ratio);
  422. dragger.minHeight = dragger.minWidth / aspectRatio;
  423. } else if (defaults.minHeight > 0) {
  424. dragger.minHeight = max(0, defaults.minHeight * ratio);
  425. dragger.minWidth = dragger.minHeight * aspectRatio;
  426. }
  427. } else {
  428. dragger.maxWidth = min(dragger.maxWidth, defaults.maxWidth * ratio);
  429. dragger.maxHeight = min(dragger.maxHeight, defaults.maxHeight * ratio);
  430. dragger.minWidth = max(0, defaults.minWidth * ratio);
  431. dragger.minHeight = max(0, defaults.minHeight * ratio);
  432. }
  433. // minWidth can't be greater than maxWidth, and minHeight too.
  434. dragger.minWidth = min(dragger.maxWidth, dragger.minWidth);
  435. dragger.minHeight = min(dragger.maxHeight, dragger.minHeight);
  436. // Center the dragger by default
  437. dragger.height *= defaults.autoCropArea;
  438. dragger.width *= defaults.autoCropArea;
  439. dragger.left = (cropper.width - dragger.width) / 2;
  440. dragger.top = (cropper.height - dragger.height) / 2;
  441. dragger.oldLeft = dragger.left;
  442. dragger.oldTop = dragger.top;
  443. this.defaultDragger = dragger;
  444. this.dragger = $.extend({}, dragger);
  445. },
  446. renderDragger: function () {
  447. var dragger = this.dragger,
  448. cropper = this.cropper;
  449. if (dragger.width > dragger.maxWidth) {
  450. dragger.width = dragger.maxWidth;
  451. dragger.left = dragger.oldLeft;
  452. } else if (dragger.width < dragger.minWidth) {
  453. dragger.width = dragger.minWidth;
  454. dragger.left = dragger.oldLeft;
  455. }
  456. if (dragger.height > dragger.maxHeight) {
  457. dragger.height = dragger.maxHeight;
  458. dragger.top = dragger.oldTop;
  459. } else if (dragger.height < dragger.minHeight) {
  460. dragger.height = dragger.minHeight;
  461. dragger.top = dragger.oldTop;
  462. }
  463. dragger.left = min(max(dragger.left, 0), cropper.width - dragger.width);
  464. dragger.top = min(max(dragger.top, 0), cropper.height - dragger.height);
  465. dragger.oldLeft = dragger.left;
  466. dragger.oldTop = dragger.top;
  467. // Re-render the dragger
  468. this.dragger = dragger;
  469. if (!this.disabled) {
  470. this.defaults.done(this.getData());
  471. }
  472. this.$dragger.css({
  473. width: dragger.width,
  474. height: dragger.height,
  475. left: dragger.left,
  476. top: dragger.top
  477. });
  478. this.preview();
  479. },
  480. reset: function (deep) {
  481. if (!this.cropped) {
  482. return;
  483. }
  484. if (deep) {
  485. this.defaults.data = {};
  486. }
  487. this.image = $.extend({}, this.defaultImage);
  488. this.renderImage();
  489. this.dragger = $.extend({}, this.defaultDragger);
  490. this.setData(this.defaults.data);
  491. },
  492. clear: function () {
  493. if (!this.cropped) {
  494. return;
  495. }
  496. this.cropped = FALSE;
  497. this.setData({
  498. x: 0,
  499. y: 0,
  500. width: 0,
  501. height: 0
  502. });
  503. this.$canvas.removeClass(CLASS_MODAL);
  504. this.$dragger.addClass(CLASS_HIDDEN);
  505. },
  506. destroy: function () {
  507. var $this = this.$element;
  508. if (!this.ready) {
  509. return;
  510. }
  511. this.unbuild();
  512. $this.removeClass(CLASS_HIDDEN).removeData("cropper");
  513. if (this.rotated) {
  514. $this.attr("src", this.$original.attr("src"));
  515. }
  516. },
  517. replace: function (url, /*INTERNAL*/ rotated) {
  518. var _this = this,
  519. $this = this.$element,
  520. element = this.element,
  521. context;
  522. if (url && url !== this.url && url !== $this.attr("src")) {
  523. if (!rotated) {
  524. this.rotated = FALSE;
  525. this.replaced = TRUE;
  526. }
  527. if ($this.is("img")) {
  528. $this.attr("src", url);
  529. this.load();
  530. } else if ($this.is("canvas") && this.support.canvas) {
  531. context = element.getContext("2d");
  532. $('<img src="' + url + '">').one("load", function () {
  533. element.width = this.width;
  534. element.height = this.height;
  535. context.clearRect(0, 0, element.width, element.height);
  536. context.drawImage(this, 0, 0);
  537. _this.load();
  538. });
  539. }
  540. }
  541. },
  542. setData: function (data, /*INTERNAL*/ once) {
  543. var cropper = this.cropper,
  544. dragger = this.dragger,
  545. image = this.image,
  546. aspectRatio = this.defaults.aspectRatio;
  547. if (!this.built || typeof data === STRING_UNDEFINED) {
  548. return;
  549. }
  550. if (data === NULL || $.isEmptyObject(data)) {
  551. dragger = $.extend({}, this.defaultDragger);
  552. }
  553. if ($.isPlainObject(data) && !$.isEmptyObject(data)) {
  554. if (!once) {
  555. this.defaults.data = data;
  556. }
  557. data = this.transformData(data);
  558. if (isNumber(data.x) && data.x <= cropper.width - image.left) {
  559. dragger.left = data.x + image.left;
  560. }
  561. if (isNumber(data.y) && data.y <= cropper.height - image.top) {
  562. dragger.top = data.y + image.top;
  563. }
  564. if (aspectRatio) {
  565. if (isNumber(data.width) && data.width <= dragger.maxWidth && data.width >= dragger.minWidth) {
  566. dragger.width = data.width;
  567. dragger.height = dragger.width / aspectRatio;
  568. } else if (isNumber(data.height) && data.height <= dragger.maxHeight && data.height >= dragger.minHeight) {
  569. dragger.height = data.height;
  570. dragger.width = dragger.height * aspectRatio;
  571. }
  572. } else {
  573. if (isNumber(data.width) && data.width <= dragger.maxWidth && data.width >= dragger.minWidth) {
  574. dragger.width = data.width;
  575. }
  576. if (isNumber(data.height) && data.height <= dragger.maxHeight && data.height >= dragger.minHeight) {
  577. dragger.height = data.height;
  578. }
  579. }
  580. }
  581. this.dragger = dragger;
  582. this.renderDragger();
  583. },
  584. getData: function (rounded) {
  585. var dragger = this.dragger,
  586. image = this.image,
  587. data = {};
  588. if (this.built) {
  589. data = {
  590. x: dragger.left - image.left,
  591. y: dragger.top - image.top,
  592. width: dragger.width,
  593. height: dragger.height
  594. };
  595. data = this.transformData(data, TRUE, rounded);
  596. }
  597. return data;
  598. },
  599. transformData: function (data, reversed, rounded) {
  600. var ratio = this.image.ratio,
  601. result = {};
  602. $.each(data, function (i, n) {
  603. n = num(n);
  604. if (REGEXP_OPTIONS.test(i) && !isNaN(n)) {
  605. result[i] = reversed ? (rounded ? Math.round(n / ratio) : n / ratio) : n * ratio;
  606. }
  607. });
  608. return result;
  609. },
  610. setAspectRatio: function (aspectRatio) {
  611. var freeRatio = aspectRatio === "auto";
  612. aspectRatio = num(aspectRatio);
  613. if (freeRatio || (!isNaN(aspectRatio) && aspectRatio > 0)) {
  614. this.defaults.aspectRatio = freeRatio ? NAN : aspectRatio;
  615. if (this.built) {
  616. this.initDragger();
  617. this.renderDragger();
  618. }
  619. }
  620. },
  621. getImageData: function () {
  622. var data = {};
  623. if (this.ready) {
  624. $.each(this.image, function (name, value) {
  625. if (REGEXP_PROPERTIES.test(name)) {
  626. data[name] = value;
  627. }
  628. });
  629. }
  630. return data;
  631. },
  632. getDataURL: function (options, type, quality) {
  633. var canvas = $("<canvas>")[0],
  634. data = this.getData(),
  635. dataURL = "",
  636. context;
  637. if (!$.isPlainObject(options)) {
  638. quality = type;
  639. type = options;
  640. options = {};
  641. }
  642. options = $.extend({
  643. width: data.width,
  644. height: data.height
  645. }, options);
  646. if (this.cropped && this.support.canvas) {
  647. canvas.width = options.width;
  648. canvas.height = options.height;
  649. context = canvas.getContext("2d");
  650. if (type === "image/jpeg") {
  651. context.fillStyle = "#fff";
  652. context.fillRect(0, 0, options.width, options.height);
  653. }
  654. context.drawImage(this.$clone[0], data.x, data.y, data.width, data.height, 0, 0, options.width, options.height);
  655. dataURL = canvas.toDataURL(type, quality);
  656. }
  657. return dataURL;
  658. },
  659. setDragMode: function (mode) {
  660. var $canvas = this.$canvas,
  661. defaults = this.defaults,
  662. cropable = FALSE,
  663. movable = FALSE;
  664. if (!this.built || this.disabled) {
  665. return;
  666. }
  667. switch (mode) {
  668. case "crop":
  669. if (defaults.dragCrop) {
  670. cropable = TRUE;
  671. $canvas.data(STRING_DIRECTIVE, mode);
  672. }
  673. break;
  674. case "move":
  675. movable = TRUE;
  676. $canvas.data(STRING_DIRECTIVE, mode);
  677. break;
  678. default:
  679. $canvas.removeData(STRING_DIRECTIVE);
  680. }
  681. $canvas.toggleClass(CLASS_CROP, cropable).toggleClass(CLASS_MOVE, movable);
  682. },
  683. enable: function () {
  684. if (this.built) {
  685. this.disabled = FALSE;
  686. this.$cropper.removeClass(CLASS_DISABLED);
  687. }
  688. },
  689. disable: function () {
  690. if (this.built) {
  691. this.disabled = TRUE;
  692. this.$cropper.addClass(CLASS_DISABLED);
  693. }
  694. },
  695. rotate: function (degree) {
  696. var image = this.image;
  697. degree = num(degree) || 0;
  698. if (!this.built || degree === 0 || this.disabled || !this.defaults.rotatable || !this.support.canvas) {
  699. return;
  700. }
  701. this.rotated = TRUE;
  702. degree = (image.rotate = (image.rotate + degree) % 360);
  703. // replace with "true" to prevent to override the original image
  704. this.replace(this.getRotatedDataURL(degree), true);
  705. },
  706. getRotatedDataURL: function (degree) {
  707. var canvas = $("<canvas>")[0],
  708. context = canvas.getContext("2d"),
  709. arc = degree * Math.PI / 180,
  710. deg = abs(degree) % 180,
  711. acuteAngle = deg > 90 ? (180 - deg) : deg,
  712. acuteAngleArc = acuteAngle * Math.PI / 180,
  713. originalImage = this.originalImage,
  714. naturalWidth = originalImage.naturalWidth,
  715. naturalHeight = originalImage.naturalHeight,
  716. width = abs(naturalWidth * cos(acuteAngleArc) + naturalHeight * sin(acuteAngleArc)),
  717. height = abs(naturalWidth * sin(acuteAngleArc) + naturalHeight * cos(acuteAngleArc));
  718. canvas.width = width;
  719. canvas.height = height;
  720. context.save();
  721. context.translate(width / 2, height / 2);
  722. context.rotate(arc);
  723. context.drawImage(this.$original[0], -naturalWidth / 2, -naturalHeight / 2, naturalWidth, naturalHeight);
  724. context.restore();
  725. return canvas.toDataURL();
  726. },
  727. zoom: function (delta) {
  728. var image = this.image,
  729. width,
  730. height,
  731. range;
  732. delta = num(delta);
  733. if (!this.built || !delta || this.disabled || !this.defaults.zoomable) {
  734. return;
  735. }
  736. width = image.width * (1 + delta);
  737. height = image.height * (1 + delta);
  738. range = width / image._width;
  739. if (range > 10) {
  740. return;
  741. }
  742. if (range < 1) {
  743. width = image._width;
  744. height = image._height;
  745. }
  746. if (range <= 1) {
  747. this.setDragMode("crop");
  748. } else {
  749. this.setDragMode("move");
  750. }
  751. image.oldWidth = image.width;
  752. image.oldHeight = image.height;
  753. image.width = width;
  754. image.height = height;
  755. image.ratio = image.width / image.naturalWidth;
  756. this.renderImage("zoom");
  757. },
  758. dblclick: function () {
  759. if (this.disabled) {
  760. return;
  761. }
  762. if (this.$canvas.hasClass(CLASS_CROP)) {
  763. this.setDragMode("move");
  764. } else {
  765. this.setDragMode("crop");
  766. }
  767. },
  768. wheel: function (event) {
  769. var e = event.originalEvent,
  770. msDeltaY = 117.25, // IE
  771. mozDelatY = 5, // Firefox
  772. webkitDelatY = 166.66665649414062, // Chrome, Opera
  773. zoomDelta = 0.1, // 10%
  774. delta;
  775. if (this.disabled) {
  776. return;
  777. }
  778. event.preventDefault();
  779. if (e.deltaY) {
  780. delta = e.deltaY;
  781. delta = delta % mozDelatY === 0 ? delta / mozDelatY : delta % msDeltaY === 0 ? delta / msDeltaY : delta / webkitDelatY;
  782. } else {
  783. delta = e.wheelDelta ? -e.wheelDelta / 120 : (e.detail ? e.detail / 3 : 0);
  784. }
  785. this.zoom(delta * zoomDelta);
  786. },
  787. dragstart: function (event) {
  788. var touches = event.originalEvent.touches,
  789. e = event,
  790. directive,
  791. dragStartEvent,
  792. touchesLength;
  793. if (this.disabled) {
  794. return;
  795. }
  796. if (touches) {
  797. touchesLength = touches.length;
  798. if (touchesLength > 1) {
  799. if (this.defaults.zoomable && touchesLength === 2) {
  800. e = touches[1];
  801. this.startX2 = e.pageX;
  802. this.startY2 = e.pageY;
  803. directive = "zoom";
  804. } else {
  805. return;
  806. }
  807. }
  808. e = touches[0];
  809. }
  810. directive = directive || $(e.target).data(STRING_DIRECTIVE);
  811. if (REGEXP_DIRECTIVES.test(directive)) {
  812. event.preventDefault();
  813. dragStartEvent = $.Event(EVENT_DRAG_START);
  814. this.$element.trigger(dragStartEvent);
  815. if (dragStartEvent.isDefaultPrevented()) {
  816. return;
  817. }
  818. this.directive = directive;
  819. this.cropping = FALSE;
  820. this.startX = e.pageX;
  821. this.startY = e.pageY;
  822. if (directive === "crop") {
  823. this.cropping = TRUE;
  824. this.$canvas.addClass(CLASS_MODAL);
  825. }
  826. }
  827. },
  828. dragmove: function (event) {
  829. var touches = event.originalEvent.touches,
  830. e = event,
  831. dragMoveEvent,
  832. touchesLength;
  833. if (this.disabled) {
  834. return;
  835. }
  836. if (touches) {
  837. touchesLength = touches.length;
  838. if (touchesLength > 1) {
  839. if (this.defaults.zoomable && touchesLength === 2) {
  840. e = touches[1];
  841. this.endX2 = e.pageX;
  842. this.endY2 = e.pageY;
  843. } else {
  844. return;
  845. }
  846. }
  847. e = touches[0];
  848. }
  849. if (this.directive) {
  850. event.preventDefault();
  851. dragMoveEvent = $.Event(EVENT_DRAG_MOVE);
  852. this.$element.trigger(dragMoveEvent);
  853. if (dragMoveEvent.isDefaultPrevented()) {
  854. return;
  855. }
  856. this.endX = e.pageX;
  857. this.endY = e.pageY;
  858. this.dragging();
  859. }
  860. },
  861. dragend: function (event) {
  862. var dragEndEvent;
  863. if (this.disabled) {
  864. return;
  865. }
  866. if (this.directive) {
  867. event.preventDefault();
  868. dragEndEvent = $.Event(EVENT_DRAG_END);
  869. this.$element.trigger(dragEndEvent);
  870. if (dragEndEvent.isDefaultPrevented()) {
  871. return;
  872. }
  873. if (this.cropping) {
  874. this.cropping = FALSE;
  875. this.$canvas.toggleClass(CLASS_MODAL, this.cropped && this.defaults.modal);
  876. }
  877. this.directive = "";
  878. }
  879. },
  880. dragging: function () {
  881. var directive = this.directive,
  882. image = this.image,
  883. cropper = this.cropper,
  884. maxWidth = cropper.width,
  885. maxHeight = cropper.height,
  886. dragger = this.dragger,
  887. width = dragger.width,
  888. height = dragger.height,
  889. left = dragger.left,
  890. top = dragger.top,
  891. right = left + width,
  892. bottom = top + height,
  893. renderable = TRUE,
  894. defaults = this.defaults,
  895. aspectRatio = defaults.aspectRatio,
  896. range = {
  897. x: this.endX - this.startX,
  898. y: this.endY - this.startY
  899. },
  900. offset;
  901. if (aspectRatio) {
  902. range.X = range.y * aspectRatio;
  903. range.Y = range.x / aspectRatio;
  904. }
  905. switch (directive) {
  906. // Move dragger
  907. case "all":
  908. left += range.x;
  909. top += range.y;
  910. break;
  911. // Resize dragger
  912. case "e":
  913. if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= 0 || bottom >= maxHeight))) {
  914. renderable = FALSE;
  915. break;
  916. }
  917. width += range.x;
  918. if (aspectRatio) {
  919. height = width / aspectRatio;
  920. top -= range.Y / 2;
  921. }
  922. if (width < 0) {
  923. directive = "w";
  924. width = 0;
  925. }
  926. break;
  927. case "n":
  928. if (range.y <= 0 && (top <= 0 || aspectRatio && (left <= 0 || right >= maxWidth))) {
  929. renderable = FALSE;
  930. break;
  931. }
  932. height -= range.y;
  933. top += range.y;
  934. if (aspectRatio) {
  935. width = height * aspectRatio;
  936. left += range.X / 2;
  937. }
  938. if (height < 0) {
  939. directive = "s";
  940. height = 0;
  941. }
  942. break;
  943. case "w":
  944. if (range.x <= 0 && (left <= 0 || aspectRatio && (top <= 0 || bottom >= maxHeight))) {
  945. renderable = FALSE;
  946. break;
  947. }
  948. width -= range.x;
  949. left += range.x;
  950. if (aspectRatio) {
  951. height = width / aspectRatio;
  952. top += range.Y / 2;
  953. }
  954. if (width < 0) {
  955. directive = "e";
  956. width = 0;
  957. }
  958. break;
  959. case "s":
  960. if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= 0 || right >= maxWidth))) {
  961. renderable = FALSE;
  962. break;
  963. }
  964. height += range.y;
  965. if (aspectRatio) {
  966. width = height * aspectRatio;
  967. left -= range.X / 2;
  968. }
  969. if (height < 0) {
  970. directive = "n";
  971. height = 0;
  972. }
  973. break;
  974. case "ne":
  975. if (aspectRatio) {
  976. if (range.y <= 0 && (top <= 0 || right >= maxWidth)) {
  977. renderable = FALSE;
  978. break;
  979. }
  980. height -= range.y;
  981. top += range.y;
  982. width = height * aspectRatio;
  983. } else {
  984. if (range.x >= 0) {
  985. if (right < maxWidth) {
  986. width += range.x;
  987. } else if (range.y <= 0 && top <= 0) {
  988. renderable = FALSE;
  989. }
  990. } else {
  991. width += range.x;
  992. }
  993. if (range.y <= 0) {
  994. if (top > 0) {
  995. height -= range.y;
  996. top += range.y;
  997. }
  998. } else {
  999. height -= range.y;
  1000. top += range.y;
  1001. }
  1002. }
  1003. if (height < 0) {
  1004. directive = "sw";
  1005. height = 0;
  1006. width = 0;
  1007. }
  1008. break;
  1009. case "nw":
  1010. if (aspectRatio) {
  1011. if (range.y <= 0 && (top <= 0 || left <= 0)) {
  1012. renderable = FALSE;
  1013. break;
  1014. }
  1015. height -= range.y;
  1016. top += range.y;
  1017. width = height * aspectRatio;
  1018. left += range.X;
  1019. } else {
  1020. if (range.x <= 0) {
  1021. if (left > 0) {
  1022. width -= range.x;
  1023. left += range.x;
  1024. } else if (range.y <= 0 && top <= 0) {
  1025. renderable = FALSE;
  1026. }
  1027. } else {
  1028. width -= range.x;
  1029. left += range.x;
  1030. }
  1031. if (range.y <= 0) {
  1032. if (top > 0) {
  1033. height -= range.y;
  1034. top += range.y;
  1035. }
  1036. } else {
  1037. height -= range.y;
  1038. top += range.y;
  1039. }
  1040. }
  1041. if (height < 0) {
  1042. directive = "se";
  1043. height = 0;
  1044. width = 0;
  1045. }
  1046. break;
  1047. case "sw":
  1048. if (aspectRatio) {
  1049. if (range.x <= 0 && (left <= 0 || bottom >= maxHeight)) {
  1050. renderable = FALSE;
  1051. break;
  1052. }
  1053. width -= range.x;
  1054. left += range.x;
  1055. height = width / aspectRatio;
  1056. } else {
  1057. if (range.x <= 0) {
  1058. if (left > 0) {
  1059. width -= range.x;
  1060. left += range.x;
  1061. } else if (range.y >= 0 && bottom >= maxHeight) {
  1062. renderable = FALSE;
  1063. }
  1064. } else {
  1065. width -= range.x;
  1066. left += range.x;
  1067. }
  1068. if (range.y >= 0) {
  1069. if (bottom < maxHeight) {
  1070. height += range.y;
  1071. }
  1072. } else {
  1073. height += range.y;
  1074. }
  1075. }
  1076. if (width < 0) {
  1077. directive = "ne";
  1078. height = 0;
  1079. width = 0;
  1080. }
  1081. break;
  1082. case "se":
  1083. if (aspectRatio) {
  1084. if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
  1085. renderable = FALSE;
  1086. break;
  1087. }
  1088. width += range.x;
  1089. height = width / aspectRatio;
  1090. } else {
  1091. if (range.x >= 0) {
  1092. if (right < maxWidth) {
  1093. width += range.x;
  1094. } else if (range.y >= 0 && bottom >= maxHeight) {
  1095. renderable = FALSE;
  1096. }
  1097. } else {
  1098. width += range.x;
  1099. }
  1100. if (range.y >= 0) {
  1101. if (bottom < maxHeight) {
  1102. height += range.y;
  1103. }
  1104. } else {
  1105. height += range.y;
  1106. }
  1107. }
  1108. if (width < 0) {
  1109. directive = "nw";
  1110. height = 0;
  1111. width = 0;
  1112. }
  1113. break;
  1114. // Move image
  1115. case "move":
  1116. image.left += range.x;
  1117. image.top += range.y;
  1118. this.renderImage("move");
  1119. renderable = FALSE;
  1120. break;
  1121. // Scale image
  1122. case "zoom":
  1123. if (defaults.zoomable) {
  1124. this.zoom(function (x, y, x1, y1, x2, y2) {
  1125. return (sqrt(x2 * x2 + y2 * y2) - sqrt(x1 * x1 + y1 * y1)) / sqrt(x * x + y * y);
  1126. }(
  1127. image.width,
  1128. image.height,
  1129. abs(this.startX - this.startX2),
  1130. abs(this.startY - this.startY2),
  1131. abs(this.endX - this.endX2),
  1132. abs(this.endY - this.endY2)
  1133. ));
  1134. this.endX2 = this.startX2;
  1135. this.endY2 = this.startY2;
  1136. }
  1137. break;
  1138. // Crop image
  1139. case "crop":
  1140. if (range.x && range.y) {
  1141. offset = this.$cropper.offset();
  1142. left = this.startX - offset.left;
  1143. top = this.startY - offset.top;
  1144. width = dragger.minWidth;
  1145. height = dragger.minHeight;
  1146. if (range.x > 0) {
  1147. if (range.y > 0) {
  1148. directive = "se";
  1149. } else {
  1150. directive = "ne";
  1151. top -= height;
  1152. }
  1153. } else {
  1154. if (range.y > 0) {
  1155. directive = "sw";
  1156. left -= width;
  1157. } else {
  1158. directive = "nw";
  1159. left -= width;
  1160. top -= height;
  1161. }
  1162. }
  1163. // Show the dragger if is hidden
  1164. if (!this.cropped) {
  1165. this.cropped = TRUE;
  1166. this.$dragger.removeClass(CLASS_HIDDEN);
  1167. }
  1168. }
  1169. break;
  1170. // No default
  1171. }
  1172. if (renderable) {
  1173. dragger.width = width;
  1174. dragger.height = height;
  1175. dragger.left = left;
  1176. dragger.top = top;
  1177. this.directive = directive;
  1178. this.renderDragger();
  1179. }
  1180. // Override
  1181. this.startX = this.endX;
  1182. this.startY = this.endY;
  1183. }
  1184. };
  1185. // Use the string compressor: Strmin (https://github.com/fengyuanchen/strmin)
  1186. Cropper.TEMPLATE = (function (source, words) {
  1187. words = words.split(",");
  1188. return source.replace(/\d+/g, function (i) {
  1189. return words[i];
  1190. });
  1191. })('<0 6="5-container"><0 6="5-canvas"></0><0 6="5-dragger"><1 6="5-viewer"></1><1 6="5-8 8-h"></1><1 6="5-8 8-v"></1><1 6="5-face" 3-2="all"></1><1 6="5-7 7-e" 3-2="e"></1><1 6="5-7 7-n" 3-2="n"></1><1 6="5-7 7-w" 3-2="w"></1><1 6="5-7 7-s" 3-2="s"></1><1 6="5-4 4-e" 3-2="e"></1><1 6="5-4 4-n" 3-2="n"></1><1 6="5-4 4-w" 3-2="w"></1><1 6="5-4 4-s" 3-2="s"></1><1 6="5-4 4-ne" 3-2="ne"></1><1 6="5-4 4-nw" 3-2="nw"></1><1 6="5-4 4-sw" 3-2="sw"></1><1 6="5-4 4-se" 3-2="se"></1></0></0>', "div,span,directive,data,point,cropper,class,line,dashed");
  1192. /* Template source:
  1193. <div class="cropper-container">
  1194. <div class="cropper-canvas"></div>
  1195. <div class="cropper-dragger">
  1196. <span class="cropper-viewer"></span>
  1197. <span class="cropper-dashed dashed-h"></span>
  1198. <span class="cropper-dashed dashed-v"></span>
  1199. <span class="cropper-face" data-directive="all"></span>
  1200. <span class="cropper-line line-e" data-directive="e"></span>
  1201. <span class="cropper-line line-n" data-directive="n"></span>
  1202. <span class="cropper-line line-w" data-directive="w"></span>
  1203. <span class="cropper-line line-s" data-directive="s"></span>
  1204. <span class="cropper-point point-e" data-directive="e"></span>
  1205. <span class="cropper-point point-n" data-directive="n"></span>
  1206. <span class="cropper-point point-w" data-directive="w"></span>
  1207. <span class="cropper-point point-s" data-directive="s"></span>
  1208. <span class="cropper-point point-ne" data-directive="ne"></span>
  1209. <span class="cropper-point point-nw" data-directive="nw"></span>
  1210. <span class="cropper-point point-sw" data-directive="sw"></span>
  1211. <span class="cropper-point point-se" data-directive="se"></span>
  1212. </div>
  1213. </div>
  1214. */
  1215. Cropper.DEFAULTS = {
  1216. // Basic
  1217. aspectRatio: "auto",
  1218. autoCropArea: 0.8, // 80%
  1219. data: {
  1220. // x: 0,
  1221. // y: 0,
  1222. // width: 300,
  1223. // height: 150
  1224. },
  1225. done: $.noop,
  1226. preview: "",
  1227. // Toggles
  1228. multiple: FALSE,
  1229. autoCrop: TRUE,
  1230. dragCrop: TRUE,
  1231. dashed: TRUE,
  1232. modal: TRUE,
  1233. movable: TRUE,
  1234. resizable: TRUE,
  1235. zoomable: TRUE,
  1236. rotatable: TRUE,
  1237. checkImageOrigin: TRUE,
  1238. // Dimensions
  1239. minWidth: 0,
  1240. minHeight: 0,
  1241. maxWidth: INFINITY,
  1242. maxHeight: INFINITY,
  1243. // Events
  1244. build: NULL,
  1245. built: NULL,
  1246. dragstart: NULL,
  1247. dragmove: NULL,
  1248. dragend: NULL
  1249. };
  1250. Cropper.setDefaults = function (options) {
  1251. $.extend(Cropper.DEFAULTS, options);
  1252. };
  1253. // Save the other cropper
  1254. Cropper.other = $.fn.cropper;
  1255. // Register as jQuery plugin
  1256. $.fn.cropper = function (options) {
  1257. var args = toArray(arguments, 1),
  1258. result;
  1259. this.each(function () {
  1260. var $this = $(this),
  1261. data = $this.data("cropper"),
  1262. fn;
  1263. if (!data) {
  1264. $this.data("cropper", (data = new Cropper(this, options)));
  1265. }
  1266. if (typeof options === "string" && $.isFunction((fn = data[options]))) {
  1267. result = fn.apply(data, args);
  1268. }
  1269. });
  1270. return (typeof result !== STRING_UNDEFINED ? result : this);
  1271. };
  1272. $.fn.cropper.Constructor = Cropper;
  1273. $.fn.cropper.setDefaults = Cropper.setDefaults;
  1274. // No conflict
  1275. $.fn.cropper.noConflict = function () {
  1276. $.fn.cropper = Cropper.other;
  1277. return this;
  1278. };
  1279. });