jcrop.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695
  1. /**
  2. * jquery.Jcrop.js v0.9.12
  3. * jQuery Image Cropping Plugin - released under MIT License
  4. * Author: Kelly Hallman <khallman@gmail.com>
  5. * http://github.com/tapmodo/Jcrop
  6. * Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{
  7. *
  8. * Permission is hereby granted, free of charge, to any person
  9. * obtaining a copy of this software and associated documentation
  10. * files (the "Software"), to deal in the Software without
  11. * restriction, including without limitation the rights to use,
  12. * copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the
  14. * Software is furnished to do so, subject to the following
  15. * conditions:
  16. *
  17. * The above copyright notice and this permission notice shall be
  18. * included in all copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  22. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  24. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  25. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  26. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  27. * OTHER DEALINGS IN THE SOFTWARE.
  28. *
  29. * }}}
  30. */
  31. (function ($) {
  32. $.Jcrop = function (obj, opt) {
  33. var options = $.extend({}, $.Jcrop.defaults),
  34. docOffset,
  35. _ua = navigator.userAgent.toLowerCase(),
  36. is_msie = /msie/.test(_ua),
  37. ie6mode = /msie [1-6]\./.test(_ua);
  38. // Internal Methods {{{
  39. function px(n) {
  40. return Math.round(n) + 'px';
  41. }
  42. function cssClass(cl) {
  43. return options.baseClass + '-' + cl;
  44. }
  45. function supportsColorFade() {
  46. return $.fx.step.hasOwnProperty('backgroundColor');
  47. }
  48. function getPos(obj) //{{{
  49. {
  50. var pos = $(obj).offset();
  51. return [pos.left, pos.top];
  52. }
  53. //}}}
  54. function mouseAbs(e) //{{{
  55. {
  56. return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])];
  57. }
  58. //}}}
  59. function setOptions(opt) //{{{
  60. {
  61. if (typeof(opt) !== 'object') opt = {};
  62. options = $.extend(options, opt);
  63. $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) {
  64. if (typeof(options[e]) !== 'function') options[e] = function () {};
  65. });
  66. }
  67. //}}}
  68. function startDragMode(mode, pos, touch) //{{{
  69. {
  70. docOffset = getPos($img);
  71. Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');
  72. if (mode === 'move') {
  73. return Tracker.activateHandlers(createMover(pos), doneSelect, touch);
  74. }
  75. var fc = Coords.getFixed();
  76. var opp = oppLockCorner(mode);
  77. var opc = Coords.getCorner(oppLockCorner(opp));
  78. Coords.setPressed(Coords.getCorner(opp));
  79. Coords.setCurrent(opc);
  80. Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch);
  81. }
  82. //}}}
  83. function dragmodeHandler(mode, f) //{{{
  84. {
  85. return function (pos) {
  86. if (!options.aspectRatio) {
  87. switch (mode) {
  88. case 'e':
  89. pos[1] = f.y2;
  90. break;
  91. case 'w':
  92. pos[1] = f.y2;
  93. break;
  94. case 'n':
  95. pos[0] = f.x2;
  96. break;
  97. case 's':
  98. pos[0] = f.x2;
  99. break;
  100. }
  101. } else {
  102. switch (mode) {
  103. case 'e':
  104. pos[1] = f.y + 1;
  105. break;
  106. case 'w':
  107. pos[1] = f.y + 1;
  108. break;
  109. case 'n':
  110. pos[0] = f.x + 1;
  111. break;
  112. case 's':
  113. pos[0] = f.x + 1;
  114. break;
  115. }
  116. }
  117. Coords.setCurrent(pos);
  118. Selection.update();
  119. };
  120. }
  121. //}}}
  122. function createMover(pos) //{{{
  123. {
  124. var lloc = pos;
  125. KeyManager.watchKeys();
  126. return function (pos) {
  127. Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
  128. lloc = pos;
  129. Selection.update();
  130. };
  131. }
  132. //}}}
  133. function oppLockCorner(ord) //{{{
  134. {
  135. switch (ord) {
  136. case 'n':
  137. return 'sw';
  138. case 's':
  139. return 'nw';
  140. case 'e':
  141. return 'nw';
  142. case 'w':
  143. return 'ne';
  144. case 'ne':
  145. return 'sw';
  146. case 'nw':
  147. return 'se';
  148. case 'se':
  149. return 'nw';
  150. case 'sw':
  151. return 'ne';
  152. }
  153. }
  154. //}}}
  155. function createDragger(ord) //{{{
  156. {
  157. return function (e) {
  158. if (options.disabled) {
  159. return false;
  160. }
  161. if ((ord === 'move') && !options.allowMove) {
  162. return false;
  163. }
  164. // Fix position of crop area when dragged the very first time.
  165. // Necessary when crop image is in a hidden element when page is loaded.
  166. docOffset = getPos($img);
  167. btndown = true;
  168. startDragMode(ord, mouseAbs(e));
  169. e.stopPropagation();
  170. e.preventDefault();
  171. return false;
  172. };
  173. }
  174. //}}}
  175. function presize($obj, w, h) //{{{
  176. {
  177. var nw = $obj.width(),
  178. nh = $obj.height();
  179. if ((nw > w) && w > 0) {
  180. nw = w;
  181. nh = (w / $obj.width()) * $obj.height();
  182. }
  183. if ((nh > h) && h > 0) {
  184. nh = h;
  185. nw = (h / $obj.height()) * $obj.width();
  186. }
  187. xscale = $obj.width() / nw;
  188. yscale = $obj.height() / nh;
  189. $obj.width(nw).height(nh);
  190. }
  191. //}}}
  192. function unscale(c) //{{{
  193. {
  194. return {
  195. x: c.x * xscale,
  196. y: c.y * yscale,
  197. x2: c.x2 * xscale,
  198. y2: c.y2 * yscale,
  199. w: c.w * xscale,
  200. h: c.h * yscale
  201. };
  202. }
  203. //}}}
  204. function doneSelect(pos) //{{{
  205. {
  206. var c = Coords.getFixed();
  207. if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) {
  208. Selection.enableHandles();
  209. Selection.done();
  210. } else {
  211. Selection.release();
  212. }
  213. Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
  214. }
  215. //}}}
  216. function newSelection(e) //{{{
  217. {
  218. if (options.disabled) {
  219. return false;
  220. }
  221. if (!options.allowSelect) {
  222. return false;
  223. }
  224. btndown = true;
  225. docOffset = getPos($img);
  226. Selection.disableHandles();
  227. Tracker.setCursor('crosshair');
  228. var pos = mouseAbs(e);
  229. Coords.setPressed(pos);
  230. Selection.update();
  231. Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch');
  232. KeyManager.watchKeys();
  233. e.stopPropagation();
  234. e.preventDefault();
  235. return false;
  236. }
  237. //}}}
  238. function selectDrag(pos) //{{{
  239. {
  240. Coords.setCurrent(pos);
  241. Selection.update();
  242. }
  243. //}}}
  244. function newTracker() //{{{
  245. {
  246. var trk = $('<div></div>').addClass(cssClass('tracker'));
  247. if (is_msie) {
  248. trk.css({
  249. opacity: 0,
  250. backgroundColor: 'white'
  251. });
  252. }
  253. return trk;
  254. }
  255. //}}}
  256. // }}}
  257. // Initialization {{{
  258. // Sanitize some options {{{
  259. if (typeof(obj) !== 'object') {
  260. obj = $(obj)[0];
  261. }
  262. if (typeof(opt) !== 'object') {
  263. opt = {};
  264. }
  265. // }}}
  266. setOptions(opt);
  267. // Initialize some jQuery objects {{{
  268. // The values are SET on the image(s) for the interface
  269. // If the original image has any of these set, they will be reset
  270. // However, if you destroy() the Jcrop instance the original image's
  271. // character in the DOM will be as you left it.
  272. var img_css = {
  273. border: 'none',
  274. visibility: 'visible',
  275. margin: 0,
  276. padding: 0,
  277. position: 'absolute',
  278. top: 0,
  279. left: 0
  280. };
  281. var $origimg = $(obj),
  282. img_mode = true;
  283. if (obj.tagName == 'IMG') {
  284. // Fix size of crop image.
  285. // Necessary when crop image is within a hidden element when page is loaded.
  286. if ($origimg[0].width != 0 && $origimg[0].height != 0) {
  287. // Obtain dimensions from contained img element.
  288. $origimg.width($origimg[0].width);
  289. $origimg.height($origimg[0].height);
  290. } else {
  291. // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0).
  292. var tempImage = new Image();
  293. tempImage.src = $origimg[0].src;
  294. $origimg.width(tempImage.width);
  295. $origimg.height(tempImage.height);
  296. }
  297. var $img = $origimg.clone().removeAttr('id').css(img_css).show();
  298. $img.width($origimg.width());
  299. $img.height($origimg.height());
  300. $origimg.after($img).hide();
  301. } else {
  302. $img = $origimg.css(img_css).show();
  303. img_mode = false;
  304. if (options.shade === null) { options.shade = true; }
  305. }
  306. presize($img, options.boxWidth, options.boxHeight);
  307. var boundx = $img.width(),
  308. boundy = $img.height(),
  309. $div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
  310. position: 'relative',
  311. backgroundColor: options.bgColor
  312. }).insertAfter($origimg).append($img);
  313. if (options.addClass) {
  314. $div.addClass(options.addClass);
  315. }
  316. var $img2 = $('<div />'),
  317. $img_holder = $('<div />')
  318. .width('100%').height('100%').css({
  319. zIndex: 310,
  320. position: 'absolute',
  321. overflow: 'hidden'
  322. }),
  323. $hdl_holder = $('<div />')
  324. .width('100%').height('100%').css('zIndex', 320),
  325. $sel = $('<div />')
  326. .css({
  327. position: 'absolute',
  328. zIndex: 600
  329. }).dblclick(function(){
  330. var c = Coords.getFixed();
  331. options.onDblClick.call(api,c);
  332. }).insertBefore($img).append($img_holder, $hdl_holder);
  333. if (img_mode) {
  334. $img2 = $('<img />')
  335. .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),
  336. $img_holder.append($img2);
  337. }
  338. if (ie6mode) {
  339. $sel.css({
  340. overflowY: 'hidden'
  341. });
  342. }
  343. var bound = options.boundary;
  344. var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({
  345. position: 'absolute',
  346. top: px(-bound),
  347. left: px(-bound),
  348. zIndex: 290
  349. }).mousedown(newSelection);
  350. /* }}} */
  351. // Set more variables {{{
  352. var bgcolor = options.bgColor,
  353. bgopacity = options.bgOpacity,
  354. xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true,
  355. btndown, animating, shift_down;
  356. docOffset = getPos($img);
  357. // }}}
  358. // }}}
  359. // Internal Modules {{{
  360. // Touch Module {{{
  361. var Touch = (function () {
  362. // Touch support detection function adapted (under MIT License)
  363. // from code by Jeffrey Sambells - http://github.com/iamamused/
  364. function hasTouchSupport() {
  365. var support = {}, events = ['touchstart', 'touchmove', 'touchend'],
  366. el = document.createElement('div'), i;
  367. try {
  368. for(i=0; i<events.length; i++) {
  369. var eventName = events[i];
  370. eventName = 'on' + eventName;
  371. var isSupported = (eventName in el);
  372. if (!isSupported) {
  373. el.setAttribute(eventName, 'return;');
  374. isSupported = typeof el[eventName] == 'function';
  375. }
  376. support[events[i]] = isSupported;
  377. }
  378. return support.touchstart && support.touchend && support.touchmove;
  379. }
  380. catch(err) {
  381. return false;
  382. }
  383. }
  384. function detectSupport() {
  385. if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport;
  386. else return hasTouchSupport();
  387. }
  388. return {
  389. createDragger: function (ord) {
  390. return function (e) {
  391. if (options.disabled) {
  392. return false;
  393. }
  394. if ((ord === 'move') && !options.allowMove) {
  395. return false;
  396. }
  397. docOffset = getPos($img);
  398. btndown = true;
  399. startDragMode(ord, mouseAbs(Touch.cfilter(e)), true);
  400. e.stopPropagation();
  401. e.preventDefault();
  402. return false;
  403. };
  404. },
  405. newSelection: function (e) {
  406. return newSelection(Touch.cfilter(e));
  407. },
  408. cfilter: function (e){
  409. e.pageX = e.originalEvent.changedTouches[0].pageX;
  410. e.pageY = e.originalEvent.changedTouches[0].pageY;
  411. return e;
  412. },
  413. isSupported: hasTouchSupport,
  414. support: detectSupport()
  415. };
  416. }());
  417. // }}}
  418. // Coords Module {{{
  419. var Coords = (function () {
  420. var x1 = 0,
  421. y1 = 0,
  422. x2 = 0,
  423. y2 = 0,
  424. ox, oy;
  425. function setPressed(pos) //{{{
  426. {
  427. pos = rebound(pos);
  428. x2 = x1 = pos[0];
  429. y2 = y1 = pos[1];
  430. }
  431. //}}}
  432. function setCurrent(pos) //{{{
  433. {
  434. pos = rebound(pos);
  435. ox = pos[0] - x2;
  436. oy = pos[1] - y2;
  437. x2 = pos[0];
  438. y2 = pos[1];
  439. }
  440. //}}}
  441. function getOffset() //{{{
  442. {
  443. return [ox, oy];
  444. }
  445. //}}}
  446. function moveOffset(offset) //{{{
  447. {
  448. var ox = offset[0],
  449. oy = offset[1];
  450. if (0 > x1 + ox) {
  451. ox -= ox + x1;
  452. }
  453. if (0 > y1 + oy) {
  454. oy -= oy + y1;
  455. }
  456. if (boundy < y2 + oy) {
  457. oy += boundy - (y2 + oy);
  458. }
  459. if (boundx < x2 + ox) {
  460. ox += boundx - (x2 + ox);
  461. }
  462. x1 += ox;
  463. x2 += ox;
  464. y1 += oy;
  465. y2 += oy;
  466. }
  467. //}}}
  468. function getCorner(ord) //{{{
  469. {
  470. var c = getFixed();
  471. switch (ord) {
  472. case 'ne':
  473. return [c.x2, c.y];
  474. case 'nw':
  475. return [c.x, c.y];
  476. case 'se':
  477. return [c.x2, c.y2];
  478. case 'sw':
  479. return [c.x, c.y2];
  480. }
  481. }
  482. //}}}
  483. function getFixed() //{{{
  484. {
  485. if (!options.aspectRatio) {
  486. return getRect();
  487. }
  488. // This function could use some optimization I think...
  489. var aspect = options.aspectRatio,
  490. min_x = options.minSize[0] / xscale,
  491. //min_y = options.minSize[1]/yscale,
  492. max_x = options.maxSize[0] / xscale,
  493. max_y = options.maxSize[1] / yscale,
  494. rw = x2 - x1,
  495. rh = y2 - y1,
  496. rwa = Math.abs(rw),
  497. rha = Math.abs(rh),
  498. real_ratio = rwa / rha,
  499. xx, yy, w, h;
  500. if (max_x === 0) {
  501. max_x = boundx * 10;
  502. }
  503. if (max_y === 0) {
  504. max_y = boundy * 10;
  505. }
  506. if (real_ratio < aspect) {
  507. yy = y2;
  508. w = rha * aspect;
  509. xx = rw < 0 ? x1 - w : w + x1;
  510. if (xx < 0) {
  511. xx = 0;
  512. h = Math.abs((xx - x1) / aspect);
  513. yy = rh < 0 ? y1 - h : h + y1;
  514. } else if (xx > boundx) {
  515. xx = boundx;
  516. h = Math.abs((xx - x1) / aspect);
  517. yy = rh < 0 ? y1 - h : h + y1;
  518. }
  519. } else {
  520. xx = x2;
  521. h = rwa / aspect;
  522. yy = rh < 0 ? y1 - h : y1 + h;
  523. if (yy < 0) {
  524. yy = 0;
  525. w = Math.abs((yy - y1) * aspect);
  526. xx = rw < 0 ? x1 - w : w + x1;
  527. } else if (yy > boundy) {
  528. yy = boundy;
  529. w = Math.abs(yy - y1) * aspect;
  530. xx = rw < 0 ? x1 - w : w + x1;
  531. }
  532. }
  533. // Magic %-)
  534. if (xx > x1) { // right side
  535. if (xx - x1 < min_x) {
  536. xx = x1 + min_x;
  537. } else if (xx - x1 > max_x) {
  538. xx = x1 + max_x;
  539. }
  540. if (yy > y1) {
  541. yy = y1 + (xx - x1) / aspect;
  542. } else {
  543. yy = y1 - (xx - x1) / aspect;
  544. }
  545. } else if (xx < x1) { // left side
  546. if (x1 - xx < min_x) {
  547. xx = x1 - min_x;
  548. } else if (x1 - xx > max_x) {
  549. xx = x1 - max_x;
  550. }
  551. if (yy > y1) {
  552. yy = y1 + (x1 - xx) / aspect;
  553. } else {
  554. yy = y1 - (x1 - xx) / aspect;
  555. }
  556. }
  557. if (xx < 0) {
  558. x1 -= xx;
  559. xx = 0;
  560. } else if (xx > boundx) {
  561. x1 -= xx - boundx;
  562. xx = boundx;
  563. }
  564. if (yy < 0) {
  565. y1 -= yy;
  566. yy = 0;
  567. } else if (yy > boundy) {
  568. y1 -= yy - boundy;
  569. yy = boundy;
  570. }
  571. return makeObj(flipCoords(x1, y1, xx, yy));
  572. }
  573. //}}}
  574. function rebound(p) //{{{
  575. {
  576. if (p[0] < 0) p[0] = 0;
  577. if (p[1] < 0) p[1] = 0;
  578. if (p[0] > boundx) p[0] = boundx;
  579. if (p[1] > boundy) p[1] = boundy;
  580. return [Math.round(p[0]), Math.round(p[1])];
  581. }
  582. //}}}
  583. function flipCoords(x1, y1, x2, y2) //{{{
  584. {
  585. var xa = x1,
  586. xb = x2,
  587. ya = y1,
  588. yb = y2;
  589. if (x2 < x1) {
  590. xa = x2;
  591. xb = x1;
  592. }
  593. if (y2 < y1) {
  594. ya = y2;
  595. yb = y1;
  596. }
  597. return [xa, ya, xb, yb];
  598. }
  599. //}}}
  600. function getRect() //{{{
  601. {
  602. var xsize = x2 - x1,
  603. ysize = y2 - y1,
  604. delta;
  605. if (xlimit && (Math.abs(xsize) > xlimit)) {
  606. x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
  607. }
  608. if (ylimit && (Math.abs(ysize) > ylimit)) {
  609. y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
  610. }
  611. if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) {
  612. y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale);
  613. }
  614. if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) {
  615. x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale);
  616. }
  617. if (x1 < 0) {
  618. x2 -= x1;
  619. x1 -= x1;
  620. }
  621. if (y1 < 0) {
  622. y2 -= y1;
  623. y1 -= y1;
  624. }
  625. if (x2 < 0) {
  626. x1 -= x2;
  627. x2 -= x2;
  628. }
  629. if (y2 < 0) {
  630. y1 -= y2;
  631. y2 -= y2;
  632. }
  633. if (x2 > boundx) {
  634. delta = x2 - boundx;
  635. x1 -= delta;
  636. x2 -= delta;
  637. }
  638. if (y2 > boundy) {
  639. delta = y2 - boundy;
  640. y1 -= delta;
  641. y2 -= delta;
  642. }
  643. if (x1 > boundx) {
  644. delta = x1 - boundy;
  645. y2 -= delta;
  646. y1 -= delta;
  647. }
  648. if (y1 > boundy) {
  649. delta = y1 - boundy;
  650. y2 -= delta;
  651. y1 -= delta;
  652. }
  653. return makeObj(flipCoords(x1, y1, x2, y2));
  654. }
  655. //}}}
  656. function makeObj(a) //{{{
  657. {
  658. return {
  659. x: a[0],
  660. y: a[1],
  661. x2: a[2],
  662. y2: a[3],
  663. w: a[2] - a[0],
  664. h: a[3] - a[1]
  665. };
  666. }
  667. //}}}
  668. return {
  669. flipCoords: flipCoords,
  670. setPressed: setPressed,
  671. setCurrent: setCurrent,
  672. getOffset: getOffset,
  673. moveOffset: moveOffset,
  674. getCorner: getCorner,
  675. getFixed: getFixed
  676. };
  677. }());
  678. //}}}
  679. // Shade Module {{{
  680. var Shade = (function() {
  681. var enabled = false,
  682. holder = $('<div />').css({
  683. position: 'absolute',
  684. zIndex: 240,
  685. opacity: 0
  686. }),
  687. shades = {
  688. top: createShade(),
  689. left: createShade().height(boundy),
  690. right: createShade().height(boundy),
  691. bottom: createShade()
  692. };
  693. function resizeShades(w,h) {
  694. shades.left.css({ height: px(h) });
  695. shades.right.css({ height: px(h) });
  696. }
  697. function updateAuto()
  698. {
  699. return updateShade(Coords.getFixed());
  700. }
  701. function updateShade(c)
  702. {
  703. shades.top.css({
  704. left: px(c.x),
  705. width: px(c.w),
  706. height: px(c.y)
  707. });
  708. shades.bottom.css({
  709. top: px(c.y2),
  710. left: px(c.x),
  711. width: px(c.w),
  712. height: px(boundy-c.y2)
  713. });
  714. shades.right.css({
  715. left: px(c.x2),
  716. width: px(boundx-c.x2)
  717. });
  718. shades.left.css({
  719. width: px(c.x)
  720. });
  721. }
  722. function createShade() {
  723. return $('<div />').css({
  724. position: 'absolute',
  725. backgroundColor: options.shadeColor||options.bgColor
  726. }).appendTo(holder);
  727. }
  728. function enableShade() {
  729. if (!enabled) {
  730. enabled = true;
  731. holder.insertBefore($img);
  732. updateAuto();
  733. Selection.setBgOpacity(1,0,1);
  734. $img2.hide();
  735. setBgColor(options.shadeColor||options.bgColor,1);
  736. if (Selection.isAwake())
  737. {
  738. setOpacity(options.bgOpacity,1);
  739. }
  740. else setOpacity(1,1);
  741. }
  742. }
  743. function setBgColor(color,now) {
  744. colorChangeMacro(getShades(),color,now);
  745. }
  746. function disableShade() {
  747. if (enabled) {
  748. holder.remove();
  749. $img2.show();
  750. enabled = false;
  751. if (Selection.isAwake()) {
  752. Selection.setBgOpacity(options.bgOpacity,1,1);
  753. } else {
  754. Selection.setBgOpacity(1,1,1);
  755. Selection.disableHandles();
  756. }
  757. colorChangeMacro($div,0,1);
  758. }
  759. }
  760. function setOpacity(opacity,now) {
  761. if (enabled) {
  762. if (options.bgFade && !now) {
  763. holder.animate({
  764. opacity: 1-opacity
  765. },{
  766. queue: false,
  767. duration: options.fadeTime
  768. });
  769. }
  770. else holder.css({opacity:1-opacity});
  771. }
  772. }
  773. function refreshAll() {
  774. options.shade ? enableShade() : disableShade();
  775. if (Selection.isAwake()) setOpacity(options.bgOpacity);
  776. }
  777. function getShades() {
  778. return holder.children();
  779. }
  780. return {
  781. update: updateAuto,
  782. updateRaw: updateShade,
  783. getShades: getShades,
  784. setBgColor: setBgColor,
  785. enable: enableShade,
  786. disable: disableShade,
  787. resize: resizeShades,
  788. refresh: refreshAll,
  789. opacity: setOpacity
  790. };
  791. }());
  792. // }}}
  793. // Selection Module {{{
  794. var Selection = (function () {
  795. var awake,
  796. hdep = 370,
  797. borders = {},
  798. handle = {},
  799. dragbar = {},
  800. seehandles = false;
  801. // Private Methods
  802. function insertBorder(type) //{{{
  803. {
  804. var jq = $('<div />').css({
  805. position: 'absolute',
  806. opacity: options.borderOpacity
  807. }).addClass(cssClass(type));
  808. $img_holder.append(jq);
  809. return jq;
  810. }
  811. //}}}
  812. function dragDiv(ord, zi) //{{{
  813. {
  814. var jq = $('<div />').mousedown(createDragger(ord)).css({
  815. cursor: ord + '-resize',
  816. position: 'absolute',
  817. zIndex: zi
  818. }).addClass('ord-'+ord);
  819. if (Touch.support) {
  820. jq.bind('touchstart.jcrop', Touch.createDragger(ord));
  821. }
  822. $hdl_holder.append(jq);
  823. return jq;
  824. }
  825. //}}}
  826. function insertHandle(ord) //{{{
  827. {
  828. var hs = options.handleSize,
  829. div = dragDiv(ord, hdep++).css({
  830. opacity: options.handleOpacity
  831. }).addClass(cssClass('handle'));
  832. if (hs) { div.width(hs).height(hs); }
  833. return div;
  834. }
  835. //}}}
  836. function insertDragbar(ord) //{{{
  837. {
  838. return dragDiv(ord, hdep++).addClass('jcrop-dragbar');
  839. }
  840. //}}}
  841. function createDragbars(li) //{{{
  842. {
  843. var i;
  844. for (i = 0; i < li.length; i++) {
  845. dragbar[li[i]] = insertDragbar(li[i]);
  846. }
  847. }
  848. //}}}
  849. function createBorders(li) //{{{
  850. {
  851. var cl,i;
  852. for (i = 0; i < li.length; i++) {
  853. switch(li[i]){
  854. case'n': cl='hline'; break;
  855. case's': cl='hline bottom'; break;
  856. case'e': cl='vline right'; break;
  857. case'w': cl='vline'; break;
  858. }
  859. borders[li[i]] = insertBorder(cl);
  860. }
  861. }
  862. //}}}
  863. function createHandles(li) //{{{
  864. {
  865. var i;
  866. for (i = 0; i < li.length; i++) {
  867. handle[li[i]] = insertHandle(li[i]);
  868. }
  869. }
  870. //}}}
  871. function moveto(x, y) //{{{
  872. {
  873. if (!options.shade) {
  874. $img2.css({
  875. top: px(-y),
  876. left: px(-x)
  877. });
  878. }
  879. $sel.css({
  880. top: px(y),
  881. left: px(x)
  882. });
  883. }
  884. //}}}
  885. function resize(w, h) //{{{
  886. {
  887. $sel.width(Math.round(w)).height(Math.round(h));
  888. }
  889. //}}}
  890. function refresh() //{{{
  891. {
  892. var c = Coords.getFixed();
  893. Coords.setPressed([c.x, c.y]);
  894. Coords.setCurrent([c.x2, c.y2]);
  895. updateVisible();
  896. }
  897. //}}}
  898. // Internal Methods
  899. function updateVisible(select) //{{{
  900. {
  901. if (awake) {
  902. return update(select);
  903. }
  904. }
  905. //}}}
  906. function update(select) //{{{
  907. {
  908. var c = Coords.getFixed();
  909. resize(c.w, c.h);
  910. moveto(c.x, c.y);
  911. if (options.shade) Shade.updateRaw(c);
  912. awake || show();
  913. if (select) {
  914. options.onSelect.call(api, unscale(c));
  915. } else {
  916. options.onChange.call(api, unscale(c));
  917. }
  918. }
  919. //}}}
  920. function setBgOpacity(opacity,force,now) //{{{
  921. {
  922. if (!awake && !force) return;
  923. if (options.bgFade && !now) {
  924. $img.animate({
  925. opacity: opacity
  926. },{
  927. queue: false,
  928. duration: options.fadeTime
  929. });
  930. } else {
  931. $img.css('opacity', opacity);
  932. }
  933. }
  934. //}}}
  935. function show() //{{{
  936. {
  937. $sel.show();
  938. if (options.shade) Shade.opacity(bgopacity);
  939. else setBgOpacity(bgopacity,true);
  940. awake = true;
  941. }
  942. //}}}
  943. function release() //{{{
  944. {
  945. disableHandles();
  946. $sel.hide();
  947. if (options.shade) Shade.opacity(1);
  948. else setBgOpacity(1);
  949. awake = false;
  950. options.onRelease.call(api);
  951. }
  952. //}}}
  953. function showHandles() //{{{
  954. {
  955. if (seehandles) {
  956. $hdl_holder.show();
  957. }
  958. }
  959. //}}}
  960. function enableHandles() //{{{
  961. {
  962. seehandles = true;
  963. if (options.allowResize) {
  964. $hdl_holder.show();
  965. return true;
  966. }
  967. }
  968. //}}}
  969. function disableHandles() //{{{
  970. {
  971. seehandles = false;
  972. $hdl_holder.hide();
  973. }
  974. //}}}
  975. function animMode(v) //{{{
  976. {
  977. if (v) {
  978. animating = true;
  979. disableHandles();
  980. } else {
  981. animating = false;
  982. enableHandles();
  983. }
  984. }
  985. //}}}
  986. function done() //{{{
  987. {
  988. animMode(false);
  989. refresh();
  990. }
  991. //}}}
  992. // Insert draggable elements {{{
  993. // Insert border divs for outline
  994. if (options.dragEdges && $.isArray(options.createDragbars))
  995. createDragbars(options.createDragbars);
  996. if ($.isArray(options.createHandles))
  997. createHandles(options.createHandles);
  998. if (options.drawBorders && $.isArray(options.createBorders))
  999. createBorders(options.createBorders);
  1000. //}}}
  1001. // This is a hack for iOS5 to support drag/move touch functionality
  1002. $(document).bind('touchstart.jcrop-ios',function(e) {
  1003. if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation();
  1004. });
  1005. var $track = newTracker().mousedown(createDragger('move')).css({
  1006. cursor: 'move',
  1007. position: 'absolute',
  1008. zIndex: 360
  1009. });
  1010. if (Touch.support) {
  1011. $track.bind('touchstart.jcrop', Touch.createDragger('move'));
  1012. }
  1013. $img_holder.append($track);
  1014. disableHandles();
  1015. return {
  1016. updateVisible: updateVisible,
  1017. update: update,
  1018. release: release,
  1019. refresh: refresh,
  1020. isAwake: function () {
  1021. return awake;
  1022. },
  1023. setCursor: function (cursor) {
  1024. $track.css('cursor', cursor);
  1025. },
  1026. enableHandles: enableHandles,
  1027. enableOnly: function () {
  1028. seehandles = true;
  1029. },
  1030. showHandles: showHandles,
  1031. disableHandles: disableHandles,
  1032. animMode: animMode,
  1033. setBgOpacity: setBgOpacity,
  1034. done: done
  1035. };
  1036. }());
  1037. //}}}
  1038. // Tracker Module {{{
  1039. var Tracker = (function () {
  1040. var onMove = function () {},
  1041. onDone = function () {},
  1042. trackDoc = options.trackDocument;
  1043. function toFront(touch) //{{{
  1044. {
  1045. $trk.css({
  1046. zIndex: 450
  1047. });
  1048. if (touch)
  1049. $(document)
  1050. .bind('touchmove.jcrop', trackTouchMove)
  1051. .bind('touchend.jcrop', trackTouchEnd);
  1052. else if (trackDoc)
  1053. $(document)
  1054. .bind('mousemove.jcrop',trackMove)
  1055. .bind('mouseup.jcrop',trackUp);
  1056. }
  1057. //}}}
  1058. function toBack() //{{{
  1059. {
  1060. $trk.css({
  1061. zIndex: 290
  1062. });
  1063. $(document).unbind('.jcrop');
  1064. }
  1065. //}}}
  1066. function trackMove(e) //{{{
  1067. {
  1068. onMove(mouseAbs(e));
  1069. return false;
  1070. }
  1071. //}}}
  1072. function trackUp(e) //{{{
  1073. {
  1074. e.preventDefault();
  1075. e.stopPropagation();
  1076. if (btndown) {
  1077. btndown = false;
  1078. onDone(mouseAbs(e));
  1079. if (Selection.isAwake()) {
  1080. options.onSelect.call(api, unscale(Coords.getFixed()));
  1081. }
  1082. toBack();
  1083. onMove = function () {};
  1084. onDone = function () {};
  1085. }
  1086. return false;
  1087. }
  1088. //}}}
  1089. function activateHandlers(move, done, touch) //{{{
  1090. {
  1091. btndown = true;
  1092. onMove = move;
  1093. onDone = done;
  1094. toFront(touch);
  1095. return false;
  1096. }
  1097. //}}}
  1098. function trackTouchMove(e) //{{{
  1099. {
  1100. onMove(mouseAbs(Touch.cfilter(e)));
  1101. return false;
  1102. }
  1103. //}}}
  1104. function trackTouchEnd(e) //{{{
  1105. {
  1106. return trackUp(Touch.cfilter(e));
  1107. }
  1108. //}}}
  1109. function setCursor(t) //{{{
  1110. {
  1111. $trk.css('cursor', t);
  1112. }
  1113. //}}}
  1114. if (!trackDoc) {
  1115. $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
  1116. }
  1117. $img.before($trk);
  1118. return {
  1119. activateHandlers: activateHandlers,
  1120. setCursor: setCursor
  1121. };
  1122. }());
  1123. //}}}
  1124. // KeyManager Module {{{
  1125. var KeyManager = (function () {
  1126. var $keymgr = $('<input type="radio" />').css({
  1127. position: 'fixed',
  1128. left: '-120px',
  1129. width: '12px'
  1130. }).addClass('jcrop-keymgr'),
  1131. $keywrap = $('<div />').css({
  1132. position: 'absolute',
  1133. overflow: 'hidden'
  1134. }).append($keymgr);
  1135. function watchKeys() //{{{
  1136. {
  1137. if (options.keySupport) {
  1138. $keymgr.show();
  1139. $keymgr.focus();
  1140. }
  1141. }
  1142. //}}}
  1143. function onBlur(e) //{{{
  1144. {
  1145. $keymgr.hide();
  1146. }
  1147. //}}}
  1148. function doNudge(e, x, y) //{{{
  1149. {
  1150. if (options.allowMove) {
  1151. Coords.moveOffset([x, y]);
  1152. Selection.updateVisible(true);
  1153. }
  1154. e.preventDefault();
  1155. e.stopPropagation();
  1156. }
  1157. //}}}
  1158. function parseKey(e) //{{{
  1159. {
  1160. if (e.ctrlKey || e.metaKey) {
  1161. return true;
  1162. }
  1163. shift_down = e.shiftKey ? true : false;
  1164. var nudge = shift_down ? 10 : 1;
  1165. switch (e.keyCode) {
  1166. case 37:
  1167. doNudge(e, -nudge, 0);
  1168. break;
  1169. case 39:
  1170. doNudge(e, nudge, 0);
  1171. break;
  1172. case 38:
  1173. doNudge(e, 0, -nudge);
  1174. break;
  1175. case 40:
  1176. doNudge(e, 0, nudge);
  1177. break;
  1178. case 27:
  1179. if (options.allowSelect) Selection.release();
  1180. break;
  1181. case 9:
  1182. return true;
  1183. }
  1184. return false;
  1185. }
  1186. //}}}
  1187. if (options.keySupport) {
  1188. $keymgr.keydown(parseKey).blur(onBlur);
  1189. if (ie6mode || !options.fixedSupport) {
  1190. $keymgr.css({
  1191. position: 'absolute',
  1192. left: '-20px'
  1193. });
  1194. $keywrap.append($keymgr).insertBefore($img);
  1195. } else {
  1196. $keymgr.insertBefore($img);
  1197. }
  1198. }
  1199. return {
  1200. watchKeys: watchKeys
  1201. };
  1202. }());
  1203. //}}}
  1204. // }}}
  1205. // API methods {{{
  1206. function setClass(cname) //{{{
  1207. {
  1208. $div.removeClass().addClass(cssClass('holder')).addClass(cname);
  1209. }
  1210. //}}}
  1211. function animateTo(a, callback) //{{{
  1212. {
  1213. var x1 = a[0] / xscale,
  1214. y1 = a[1] / yscale,
  1215. x2 = a[2] / xscale,
  1216. y2 = a[3] / yscale;
  1217. if (animating) {
  1218. return;
  1219. }
  1220. var animto = Coords.flipCoords(x1, y1, x2, y2),
  1221. c = Coords.getFixed(),
  1222. initcr = [c.x, c.y, c.x2, c.y2],
  1223. animat = initcr,
  1224. interv = options.animationDelay,
  1225. ix1 = animto[0] - initcr[0],
  1226. iy1 = animto[1] - initcr[1],
  1227. ix2 = animto[2] - initcr[2],
  1228. iy2 = animto[3] - initcr[3],
  1229. pcent = 0,
  1230. velocity = options.swingSpeed;
  1231. x1 = animat[0];
  1232. y1 = animat[1];
  1233. x2 = animat[2];
  1234. y2 = animat[3];
  1235. Selection.animMode(true);
  1236. var anim_timer;
  1237. function queueAnimator() {
  1238. window.setTimeout(animator, interv);
  1239. }
  1240. var animator = (function () {
  1241. return function () {
  1242. pcent += (100 - pcent) / velocity;
  1243. animat[0] = Math.round(x1 + ((pcent / 100) * ix1));
  1244. animat[1] = Math.round(y1 + ((pcent / 100) * iy1));
  1245. animat[2] = Math.round(x2 + ((pcent / 100) * ix2));
  1246. animat[3] = Math.round(y2 + ((pcent / 100) * iy2));
  1247. if (pcent >= 99.8) {
  1248. pcent = 100;
  1249. }
  1250. if (pcent < 100) {
  1251. setSelectRaw(animat);
  1252. queueAnimator();
  1253. } else {
  1254. Selection.done();
  1255. Selection.animMode(false);
  1256. if (typeof(callback) === 'function') {
  1257. callback.call(api);
  1258. }
  1259. }
  1260. };
  1261. }());
  1262. queueAnimator();
  1263. }
  1264. //}}}
  1265. function setSelect(rect) //{{{
  1266. {
  1267. setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]);
  1268. options.onSelect.call(api, unscale(Coords.getFixed()));
  1269. Selection.enableHandles();
  1270. }
  1271. //}}}
  1272. function setSelectRaw(l) //{{{
  1273. {
  1274. Coords.setPressed([l[0], l[1]]);
  1275. Coords.setCurrent([l[2], l[3]]);
  1276. Selection.update();
  1277. }
  1278. //}}}
  1279. function tellSelect() //{{{
  1280. {
  1281. return unscale(Coords.getFixed());
  1282. }
  1283. //}}}
  1284. function tellScaled() //{{{
  1285. {
  1286. return Coords.getFixed();
  1287. }
  1288. //}}}
  1289. function setOptionsNew(opt) //{{{
  1290. {
  1291. setOptions(opt);
  1292. interfaceUpdate();
  1293. }
  1294. //}}}
  1295. function disableCrop() //{{{
  1296. {
  1297. options.disabled = true;
  1298. Selection.disableHandles();
  1299. Selection.setCursor('default');
  1300. Tracker.setCursor('default');
  1301. }
  1302. //}}}
  1303. function enableCrop() //{{{
  1304. {
  1305. options.disabled = false;
  1306. interfaceUpdate();
  1307. }
  1308. //}}}
  1309. function cancelCrop() //{{{
  1310. {
  1311. Selection.done();
  1312. Tracker.activateHandlers(null, null);
  1313. }
  1314. //}}}
  1315. function destroy() //{{{
  1316. {
  1317. $div.remove();
  1318. $origimg.show();
  1319. $origimg.css('visibility','visible');
  1320. $(obj).removeData('Jcrop');
  1321. }
  1322. //}}}
  1323. function setImage(src, callback) //{{{
  1324. {
  1325. Selection.release();
  1326. disableCrop();
  1327. var img = new Image();
  1328. img.onload = function () {
  1329. var iw = img.width;
  1330. var ih = img.height;
  1331. var bw = options.boxWidth;
  1332. var bh = options.boxHeight;
  1333. $img.width(iw).height(ih);
  1334. $img.attr('src', src);
  1335. $img2.attr('src', src);
  1336. presize($img, bw, bh);
  1337. boundx = $img.width();
  1338. boundy = $img.height();
  1339. $img2.width(boundx).height(boundy);
  1340. $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2));
  1341. $div.width(boundx).height(boundy);
  1342. Shade.resize(boundx,boundy);
  1343. enableCrop();
  1344. if (typeof(callback) === 'function') {
  1345. callback.call(api);
  1346. }
  1347. };
  1348. img.src = src;
  1349. }
  1350. //}}}
  1351. function colorChangeMacro($obj,color,now) {
  1352. var mycolor = color || options.bgColor;
  1353. if (options.bgFade && supportsColorFade() && options.fadeTime && !now) {
  1354. $obj.animate({
  1355. backgroundColor: mycolor
  1356. }, {
  1357. queue: false,
  1358. duration: options.fadeTime
  1359. });
  1360. } else {
  1361. $obj.css('backgroundColor', mycolor);
  1362. }
  1363. }
  1364. function interfaceUpdate(alt) //{{{
  1365. // This method tweaks the interface based on options object.
  1366. // Called when options are changed and at end of initialization.
  1367. {
  1368. if (options.allowResize) {
  1369. if (alt) {
  1370. Selection.enableOnly();
  1371. } else {
  1372. Selection.enableHandles();
  1373. }
  1374. } else {
  1375. Selection.disableHandles();
  1376. }
  1377. Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
  1378. Selection.setCursor(options.allowMove ? 'move' : 'default');
  1379. if (options.hasOwnProperty('trueSize')) {
  1380. xscale = options.trueSize[0] / boundx;
  1381. yscale = options.trueSize[1] / boundy;
  1382. }
  1383. if (options.hasOwnProperty('setSelect')) {
  1384. setSelect(options.setSelect);
  1385. Selection.done();
  1386. delete(options.setSelect);
  1387. }
  1388. Shade.refresh();
  1389. if (options.bgColor != bgcolor) {
  1390. colorChangeMacro(
  1391. options.shade? Shade.getShades(): $div,
  1392. options.shade?
  1393. (options.shadeColor || options.bgColor):
  1394. options.bgColor
  1395. );
  1396. bgcolor = options.bgColor;
  1397. }
  1398. if (bgopacity != options.bgOpacity) {
  1399. bgopacity = options.bgOpacity;
  1400. if (options.shade) Shade.refresh();
  1401. else Selection.setBgOpacity(bgopacity);
  1402. }
  1403. xlimit = options.maxSize[0] || 0;
  1404. ylimit = options.maxSize[1] || 0;
  1405. xmin = options.minSize[0] || 0;
  1406. ymin = options.minSize[1] || 0;
  1407. if (options.hasOwnProperty('outerImage')) {
  1408. $img.attr('src', options.outerImage);
  1409. delete(options.outerImage);
  1410. }
  1411. Selection.refresh();
  1412. }
  1413. //}}}
  1414. //}}}
  1415. if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection);
  1416. $hdl_holder.hide();
  1417. interfaceUpdate(true);
  1418. var api = {
  1419. setImage: setImage,
  1420. animateTo: animateTo,
  1421. setSelect: setSelect,
  1422. setOptions: setOptionsNew,
  1423. tellSelect: tellSelect,
  1424. tellScaled: tellScaled,
  1425. setClass: setClass,
  1426. disable: disableCrop,
  1427. enable: enableCrop,
  1428. cancel: cancelCrop,
  1429. release: Selection.release,
  1430. destroy: destroy,
  1431. focus: KeyManager.watchKeys,
  1432. getBounds: function () {
  1433. return [boundx * xscale, boundy * yscale];
  1434. },
  1435. getWidgetSize: function () {
  1436. return [boundx, boundy];
  1437. },
  1438. getScaleFactor: function () {
  1439. return [xscale, yscale];
  1440. },
  1441. getOptions: function() {
  1442. // careful: internal values are returned
  1443. return options;
  1444. },
  1445. ui: {
  1446. holder: $div,
  1447. selection: $sel
  1448. }
  1449. };
  1450. if (is_msie) $div.bind('selectstart', function () { return false; });
  1451. $origimg.data('Jcrop', api);
  1452. return api;
  1453. };
  1454. $.fn.Jcrop = function (options, callback) //{{{
  1455. {
  1456. var api;
  1457. // Iterate over each object, attach Jcrop
  1458. this.each(function () {
  1459. // If we've already attached to this object
  1460. if ($(this).data('Jcrop')) {
  1461. // The API can be requested this way (undocumented)
  1462. if (options === 'api') return $(this).data('Jcrop');
  1463. // Otherwise, we just reset the options...
  1464. else $(this).data('Jcrop').setOptions(options);
  1465. }
  1466. // If we haven't been attached, preload and attach
  1467. else {
  1468. if (this.tagName == 'IMG')
  1469. $.Jcrop.Loader(this,function(){
  1470. $(this).css({display:'block',visibility:'hidden'});
  1471. api = $.Jcrop(this, options);
  1472. if ($.isFunction(callback)) callback.call(api);
  1473. });
  1474. else {
  1475. $(this).css({display:'block',visibility:'hidden'});
  1476. api = $.Jcrop(this, options);
  1477. if ($.isFunction(callback)) callback.call(api);
  1478. }
  1479. }
  1480. });
  1481. // Return "this" so the object is chainable (jQuery-style)
  1482. return this;
  1483. };
  1484. //}}}
  1485. // $.Jcrop.Loader - basic image loader {{{
  1486. $.Jcrop.Loader = function(imgobj,success,error){
  1487. var $img = $(imgobj), img = $img[0];
  1488. function completeCheck(){
  1489. if (img.complete) {
  1490. $img.unbind('.jcloader');
  1491. if ($.isFunction(success)) success.call(img);
  1492. }
  1493. else window.setTimeout(completeCheck,50);
  1494. }
  1495. $img
  1496. .bind('load.jcloader',completeCheck)
  1497. .bind('error.jcloader',function(e){
  1498. $img.unbind('.jcloader');
  1499. if ($.isFunction(error)) error.call(img);
  1500. });
  1501. if (img.complete && $.isFunction(success)){
  1502. $img.unbind('.jcloader');
  1503. success.call(img);
  1504. }
  1505. };
  1506. //}}}
  1507. // Global Defaults {{{
  1508. $.Jcrop.defaults = {
  1509. // Basic Settings
  1510. allowSelect: true,
  1511. allowMove: true,
  1512. allowResize: true,
  1513. trackDocument: true,
  1514. // Styling Options
  1515. baseClass: 'jcrop',
  1516. addClass: null,
  1517. bgColor: 'black',
  1518. bgOpacity: 0.6,
  1519. bgFade: false,
  1520. borderOpacity: 0.4,
  1521. handleOpacity: 0.5,
  1522. handleSize: null,
  1523. aspectRatio: 0,
  1524. keySupport: true,
  1525. createHandles: ['n','s','e','w','nw','ne','se','sw'],
  1526. createDragbars: ['n','s','e','w'],
  1527. createBorders: ['n','s','e','w'],
  1528. drawBorders: true,
  1529. dragEdges: true,
  1530. fixedSupport: true,
  1531. touchSupport: null,
  1532. shade: null,
  1533. boxWidth: 0,
  1534. boxHeight: 0,
  1535. boundary: 2,
  1536. fadeTime: 400,
  1537. animationDelay: 20,
  1538. swingSpeed: 3,
  1539. minSelect: [0, 0],
  1540. maxSize: [0, 0],
  1541. minSize: [0, 0],
  1542. // Callbacks / Event Handlers
  1543. onChange: function () {},
  1544. onSelect: function () {},
  1545. onDblClick: function () {},
  1546. onRelease: function () {}
  1547. };
  1548. // }}}
  1549. }(jQuery));