zoom.js 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. /**
  2. * zoom.js
  3. * www.turnjs.com
  4. * turnjs.com/license.txt
  5. *
  6. * Copyright (C) 2012 Emmanuel Garcia
  7. **/
  8. (function($) {
  9. 'use strict';
  10. var has3d,
  11. zoomOptions = {
  12. max: 2,
  13. flipbook: null,
  14. easeFunction: 'ease-in-out',
  15. duration: 500,
  16. when: {}
  17. },
  18. zoomMethods = {
  19. init: function(opts) {
  20. var that = this,
  21. data = this.data(),
  22. options = $.extend({}, zoomOptions, opts);
  23. if (!options.flipbook || !options.flipbook.turn('is')) {
  24. throw error('options.flipbook is required');
  25. }
  26. has3d = 'WebKitCSSMatrix' in window || 'MozPerspective' in document.body.style;
  27. if (typeof(options.max)!='function') {
  28. var max = options.max;
  29. options.max = function() { return max; };
  30. }
  31. data.zoom = {
  32. opts: options,
  33. axis: point2D(0, 0),
  34. scrollPos: point2D(0, 0),
  35. eventQueue: [],
  36. mouseupEvent: function() {
  37. return zoomMethods._eMouseUp.apply(that, arguments);
  38. },
  39. eventTouchStart: bind(zoomMethods._eTouchStart, that),
  40. eventTouchMove: bind(zoomMethods._eTouchMove, that),
  41. eventTouchEnd: bind(zoomMethods._eTouchEnd, that),
  42. flipbookEvents: {
  43. zooming: bind(zoomMethods._eZoom, that),
  44. pressed: bind(zoomMethods._ePressed, that),
  45. released: bind(zoomMethods._eReleased, that),
  46. start: bind(zoomMethods._eStart, that),
  47. turning: bind(zoomMethods._eTurning, that),
  48. turned: bind(zoomMethods._eTurned, that),
  49. destroying: bind(zoomMethods._eDestroying, that)
  50. }
  51. };
  52. for (var eventName in options.when) {
  53. if (Object.prototype.hasOwnProperty.call(options.when, eventName)) {
  54. this.bind('zoom.'+eventName, options.when[eventName]);
  55. }
  56. }
  57. for (eventName in data.zoom.flipbookEvents) {
  58. if (Object.prototype.hasOwnProperty.call(data.zoom.flipbookEvents, eventName)) {
  59. options.flipbook.bind(eventName, data.zoom.flipbookEvents[eventName]);
  60. }
  61. }
  62. this.css({
  63. position: 'relative',
  64. overflow : 'hidden'
  65. });
  66. if ($.isTouch) {
  67. options.flipbook.
  68. bind('touchstart', data.zoom.eventTouchStart ).
  69. bind('touchmove', data.zoom.eventTouchMove).
  70. bind('touchend', data.zoom.eventTouchEnd);
  71. this.bind('touchstart', zoomMethods._tap);
  72. } else {
  73. this.mousedown(zoomMethods._mousedown).
  74. click(zoomMethods._tap);
  75. }
  76. },
  77. _tap: function(event) {
  78. var that = $(this),
  79. data = that.data().zoom,
  80. flip = data.opts.flipbook;
  81. if (data.draggingCorner || data.dragging) {
  82. return;
  83. }
  84. if (isPage($(event.target), that)) {
  85. zoomMethods._addEvent.call(that, 'tap', event);
  86. var secuence = zoomMethods._eventSeq.call(that);
  87. if (secuence)
  88. that.trigger(secuence);
  89. }
  90. },
  91. _addEvent: function(eventName, event) {
  92. var data = this.data().zoom,
  93. time = (new Date()).getTime(),
  94. eventObject = {name: eventName, timestamp: time, event: event};
  95. data.eventQueue.push(eventObject);
  96. if (data.eventQueue.length>10)
  97. data.eventQueue.splice(0, 1);
  98. },
  99. _eventSeq: function() {
  100. var data = this.data().zoom,
  101. list = data.eventQueue,
  102. lastEvent = list.length-1;
  103. if (lastEvent>0 &&
  104. list[lastEvent].name=='tap' &&
  105. list[lastEvent-1].name=='tap' &&
  106. list[lastEvent].event.pageX == list[lastEvent-1].event.pageX &&
  107. list[lastEvent].event.pageY == list[lastEvent-1].event.pageY &&
  108. list[lastEvent].timestamp-list[lastEvent-1].timestamp < 200 &&
  109. list[lastEvent].timestamp-list[lastEvent-1].timestamp > 50)
  110. {
  111. return $.extend(list[lastEvent].event, {type: 'zoom.doubleTap'});
  112. } else if (list[lastEvent].name=='tap') {
  113. return $.extend(list[lastEvent].event, {type: 'zoom.tap'});
  114. }
  115. },
  116. _prepareZoom: function () {
  117. var flipPos, offsetLeft = 0,
  118. data = this.data().zoom,
  119. invz = 1/this.zoom('value'),
  120. flip = data.opts.flipbook,
  121. dir = flip.turn('direction'),
  122. flipData = flip.data(),
  123. flipOffset = flip.offset(),
  124. thisOffset = this.offset(),
  125. flipSize = {height: flip.height()},
  126. view = flip.turn('view');
  127. if (flip.turn('display')=='double' && flip.data().opts.autoCenter) {
  128. if (!view[0]) {
  129. flipSize.width = flip.width()/2;
  130. offsetLeft = (dir=='ltr') ? flipSize.width : 0;
  131. flipPos = point2D(
  132. (dir=='ltr') ? flipOffset.left-thisOffset.left+flipSize.width : flipOffset.left-thisOffset.left,
  133. flipOffset.top-thisOffset.top
  134. );
  135. } else if (!view[1]) {
  136. flipSize.width = flip.width()/2;
  137. offsetLeft = (dir=='ltr') ? 0 : flipSize.width;
  138. flipPos = point2D(
  139. (dir=='ltr') ? flipOffset.left-thisOffset.left : flipOffset.left-thisOffset.left+flipSize.width,
  140. flipOffset.top-thisOffset.top
  141. );
  142. } else {
  143. flipSize.width = flip.width();
  144. flipPos = point2D(
  145. flipOffset.left-thisOffset.left,
  146. flipOffset.top-thisOffset.top
  147. );
  148. }
  149. } else {
  150. flipSize.width = flip.width();
  151. flipPos = point2D(
  152. flipOffset.left-thisOffset.left,
  153. flipOffset.top-thisOffset.top
  154. );
  155. }
  156. if (!data.zoomer) {
  157. data.zoomer = $('<div />',
  158. {'class': 'zoomer',
  159. css: {
  160. overflow:'hidden',
  161. position: 'absolute',
  162. zIndex: '1000000'
  163. }
  164. }).
  165. mousedown(function() {
  166. return false;
  167. }).appendTo(this);
  168. }
  169. data.zoomer.css({
  170. top: flipPos.y,
  171. left: flipPos.x,
  172. width: flipSize.width,
  173. height: flipSize.height
  174. });
  175. var zoomerView = view.join(',');
  176. if (zoomerView!=data.zoomerView) {
  177. data.zoomerView = zoomerView;
  178. data.zoomer.find('*').remove();
  179. for (var p = 0; p<view.length; p++) {
  180. if (!view[p])
  181. continue;
  182. var pos = flipData.pageObjs[view[p]].offset(),
  183. pageElement = $(flipData.pageObjs[view[p]]);
  184. pageElement.
  185. clone().
  186. transform('').
  187. css({
  188. width: pageElement.width()*invz,
  189. height: pageElement.height()*invz,
  190. position: 'absolute',
  191. display: '',
  192. top: (pos.top - flipOffset.top)*invz,
  193. left: (pos.left - flipOffset.left - offsetLeft)*invz
  194. }).
  195. appendTo(data.zoomer);
  196. }
  197. }
  198. return {pos: flipPos, size: flipSize};
  199. },
  200. value: function() {
  201. var data = this.data().zoom;
  202. return data.opts.flipbook.turn('zoom');
  203. },
  204. zoomIn: function(event) {
  205. var pos,
  206. that = this,
  207. data = this.data().zoom,
  208. flip = data.opts.flipbook,
  209. zoom = data.opts.max(),
  210. flipOffset = flip.offset(),
  211. thisOffset = this.offset();
  212. if (data.zoomIn)
  213. return this;
  214. flip.turn('stop');
  215. var ev = $.Event('zoom.change');
  216. this.trigger(ev, [zoom]);
  217. if (ev.isDefaultPrevented())
  218. return this;
  219. var bound = zoomMethods._prepareZoom.call(this),
  220. flipPos = bound.pos,
  221. center = point2D(bound.size.width/2, bound.size.height/2),
  222. prefix = $.cssPrefix(),
  223. transitionEnd = $.cssTransitionEnd(),
  224. autoCenter = flip.data().opts.autoCenter;
  225. data.scale = zoom;
  226. flip.data().noCenter = true;
  227. if (typeof(event)!='undefined') {
  228. if ('x' in event && 'y' in event) {
  229. pos = point2D(event.x-flipPos.x, event.y-flipPos.y);
  230. } else {
  231. pos = ($.isTouch) ?
  232. point2D(
  233. event.originalEvent.touches[0].pageX-flipPos.x-thisOffset.left,
  234. event.originalEvent.touches[0].pageY-flipPos.y-thisOffset.top
  235. )
  236. :
  237. point2D(
  238. event.pageX-flipPos.x-thisOffset.left,
  239. event.pageY-flipPos.y-thisOffset.top
  240. );
  241. }
  242. } else {
  243. pos = point2D(center.x, center.y);
  244. }
  245. if (pos.x<0 || pos.y<0 || pos.x>bound.width || pos.y>bound.height) {
  246. pos.x = center.x;
  247. pos.y = center.y;
  248. }
  249. var compose = point2D(
  250. (pos.x-center.x)*zoom + center.x,
  251. (pos.y-center.y)*zoom + center.y
  252. ),
  253. move = point2D(
  254. (bound.size.width*zoom>this.width()) ? pos.x-compose.x : 0,
  255. (bound.size.height*zoom>this.height()) ? pos.y-compose.y : 0
  256. ),
  257. maxMove = point2D(
  258. Math.abs(bound.size.width*zoom-this.width()),
  259. Math.abs(bound.size.height*zoom-this.height())
  260. ),
  261. minMove = point2D(
  262. Math.min(0, bound.size.width*zoom-this.width()),
  263. Math.min(0, bound.size.height*zoom-this.height())
  264. ),
  265. realPos = point2D(
  266. center.x*zoom - center.x - flipPos.x - move.x,
  267. center.y*zoom - center.y - flipPos.y - move.y
  268. );
  269. if (realPos.y>maxMove.y)
  270. move.y = realPos.y - maxMove.y + move.y;
  271. else if (realPos.y<minMove.y)
  272. move.y = realPos.y - minMove.y + move.y;
  273. if (realPos.x>maxMove.x)
  274. move.x = realPos.x - maxMove.x + move.x;
  275. else if (realPos.x<minMove.x)
  276. move.x = realPos.x - minMove.x + move.x;
  277. realPos = point2D(
  278. center.x*zoom - center.x - flipPos.x - move.x,
  279. center.y*zoom - center.y - flipPos.y - move.y
  280. );
  281. var css = {};
  282. css[prefix+'transition'] = prefix +
  283. 'transform ' +
  284. data.opts.easeFunction +
  285. ' ' +
  286. data.opts.duration +
  287. 'ms';
  288. var transitionEndCallback = function() {
  289. that.trigger('zoom.zoomIn');
  290. data.zoomIn = true;
  291. data.flipPosition = point2D(flip.css('left'), flip.css('top'));
  292. flip.turn('zoom', zoom).css({
  293. position: 'absolute',
  294. margin: '',
  295. top:0,
  296. left:0
  297. });
  298. var flipOffset = flip.offset();
  299. data.axis = point2D(
  300. flipOffset.left - thisOffset.left,
  301. flipOffset.top - thisOffset.top
  302. );
  303. if (autoCenter && flip.turn('display')=='double')
  304. if ((flip.turn('direction')=='ltr' && !flip.turn('view')[0]) ||
  305. (flip.turn('direction')=='rtl' && !flip.turn('view')[1])
  306. )
  307. data.axis.x = data.axis.x + flip.width()/2;
  308. that.zoom('scroll', realPos);
  309. that.bind($.mouseEvents.down, zoomMethods._eMouseDown);
  310. that.bind($.mouseEvents.move, zoomMethods._eMouseMove);
  311. $(document).bind($.mouseEvents.up, data.mouseupEvent);
  312. that.bind('mousewheel', zoomMethods._eMouseWheel);
  313. setTimeout(function() {
  314. data.zoomer.hide();
  315. data.zoomer.remove();
  316. data.zoomer = null;
  317. data.zoomerView = null;
  318. }, 50);
  319. };
  320. data.zoomer.css(css).show();
  321. if (transitionEnd)
  322. data.zoomer.bind(transitionEnd, function() {
  323. $(this).unbind(transitionEnd);
  324. transitionEndCallback();
  325. });
  326. else
  327. setTimeout(transitionEndCallback, data.opts.duration);
  328. data.zoomer.transform(translate(move.x, move.y, true) + scale(zoom, true));
  329. return this;
  330. },
  331. zoomOut: function(duration) {
  332. var pos, move,
  333. that = this,
  334. data = this.data().zoom,
  335. flip = data.opts.flipbook,
  336. zoom = 1,
  337. scaling = zoom/data.scale,
  338. prefix = $.cssPrefix(),
  339. transitionEnd = $.cssTransitionEnd(),
  340. thisOffset = this.offset();
  341. duration = (typeof(duration)!='undefined') ? duration : data.opts.duration;
  342. if (!data.zoomIn)
  343. return;
  344. var ev = $.Event('zoom.change');
  345. this.trigger(ev, [zoom]);
  346. if (ev.isDefaultPrevented())
  347. return this;
  348. data.zoomIn = false;
  349. data.scale = zoom;
  350. flip.data().noCenter = false;
  351. that.unbind($.mouseEvents.down, zoomMethods._eMouseDown);
  352. that.unbind($.mouseEvents.move, zoomMethods._eMouseMove);
  353. $(document).unbind($.mouseEvents.up, data.mouseupEvent);
  354. that.unbind('mousewheel', zoomMethods._eMouseWheel);
  355. var css = {};
  356. css[prefix+'transition'] = prefix +
  357. 'transform ' +
  358. data.opts.easeFunction +
  359. ' ' +
  360. duration +
  361. 'ms';
  362. flip.css(css);
  363. var flipDesPos,
  364. tmp = $('<div />', {
  365. css: {
  366. position: 'relative',
  367. top: data.flipPosition.y,
  368. left: data.flipPosition.x,
  369. width: flip.width()*scaling,
  370. height: flip.height()*scaling,
  371. background: 'blue'
  372. }
  373. }).appendTo(flip.parent());
  374. flipDesPos = point2D(
  375. tmp.offset().left-thisOffset.left,
  376. tmp.offset().top-thisOffset.top
  377. );
  378. tmp.remove();
  379. var autoCenter = flip.data().opts.autoCenter;
  380. if (autoCenter && flip.turn('display')=='double') {
  381. if (!flip.turn('view')[0])
  382. flipDesPos.x = (flip.turn('direction')=='ltr') ?
  383. flipDesPos.x-tmp.width()/4 :
  384. flipDesPos.x+tmp.width()/4;
  385. else if (!flip.turn('view')[1])
  386. flipDesPos.x = (flip.turn('direction')=='ltr') ?
  387. flipDesPos.x+tmp.width()/4 :
  388. flipDesPos.x-tmp.width()/4;
  389. }
  390. var flipRealPos = $.findPos(flip[0]);
  391. move = point2D(
  392. -flip.width()/2 - flipRealPos.left + tmp.width()/2 + flipDesPos.x + thisOffset.left,
  393. -flip.height()/2 - flipRealPos.top + tmp.height()/2 + flipDesPos.y + thisOffset.top);
  394. var transitionEndCallback = function() {
  395. if (flip[0].style.removeProperty) {
  396. flip[0].style.removeProperty(prefix+'transition');
  397. flip.transform(
  398. (flip.turn('options').acceleration) ? translate(0, 0, true) : '').turn('zoom', 1);
  399. flip[0].style.removeProperty('margin');
  400. flip.css({
  401. position: 'relative',
  402. top: data.flipPosition.y,
  403. left: data.flipPosition.x
  404. });
  405. } else {
  406. flip.transform('none').
  407. turn('zoom', 1).
  408. css({
  409. margin: '',
  410. top: data.flipPosition.y,
  411. left: data.flipPosition.x,
  412. position: 'relative'
  413. });
  414. }
  415. if (autoCenter)
  416. flip.turn('center');
  417. that.trigger('zoom.zoomOut');
  418. };
  419. if (duration===0) {
  420. transitionEndCallback();
  421. } else if (transitionEnd) {
  422. flip.bind(transitionEnd, function() {
  423. $(this).unbind(transitionEnd);
  424. transitionEndCallback();
  425. });
  426. flip.transform(translate(move.x, move.y, true) + scale(scaling, true));
  427. } else {
  428. setTimeout(transitionEndCallback, duration);
  429. flip.transform(translate(move.x, move.y, true) + scale(scaling, true));
  430. }
  431. return this;
  432. },
  433. flipbookWidth: function() {
  434. var data = this.data().zoom,
  435. flipbook = data.opts.flipbook,
  436. view = flipbook.turn('view');
  437. return (flipbook.turn('display')=='double' && (!view[0] || !view[1])) ?
  438. flipbook.width()/2
  439. :
  440. flipbook.width();
  441. },
  442. scroll: function(to, unlimited, animate) {
  443. var data = this.data().zoom,
  444. flip = data.opts.flipbook,
  445. flipWidth = this.zoom('flipbookWidth'),
  446. prefix = $.cssPrefix();
  447. if (has3d) {
  448. var css = {};
  449. if (animate) {
  450. css[prefix+'transition'] = prefix + 'transform 200ms';
  451. } else {
  452. css[prefix+'transition'] = 'none';
  453. }
  454. flip.css(css);
  455. flip.transform(translate(-data.axis.x - to.x, -data.axis.y - to.y, true));
  456. } else {
  457. flip.css({top: -data.axis.y - to.y, left: -data.axis.x - to.x});
  458. }
  459. if (!unlimited) {
  460. var out,
  461. minBound = point2D(
  462. Math.min(0, (flipWidth-this.width())/2),
  463. Math.min(0, (flip.height()-this.height())/2)),
  464. maxBound = point2D(
  465. (flipWidth>this.width()) ? flipWidth-this.width() : (flipWidth-this.width())/2,
  466. (flip.height()>this.height()) ? flip.height()-this.height() : (flip.height()-this.height())/2
  467. );
  468. if (to.y<minBound.y) {
  469. to.y = minBound.y;
  470. out = true;
  471. } else if (to.y>maxBound.y) {
  472. to.y = maxBound.y;
  473. out = true;
  474. }
  475. if (to.x<minBound.x) {
  476. to.x = minBound.x;
  477. out = true;
  478. } else if (to.x>maxBound.x) {
  479. to.x = maxBound.x;
  480. out = true;
  481. }
  482. if (out) {
  483. this.zoom('scroll', to, true, true);
  484. }
  485. }
  486. data.scrollPos = point2D(to.x, to.y);
  487. },
  488. resize: function() {
  489. var data = this.data().zoom,
  490. flip = data.opts.flipbook;
  491. if (this.zoom('value')>1) {
  492. var flipOffset = flip.offset(),
  493. thisOffset = this.offset();
  494. data.axis = point2D(
  495. (flipOffset.left - thisOffset.left) + (data.axis.x + data.scrollPos.x),
  496. (flipOffset.top - thisOffset.top) + (data.axis.y + data.scrollPos.y)
  497. );
  498. if (flip.turn('display')=='double' &&
  499. flip.turn('direction')=='ltr' &&
  500. !flip.turn('view')[0])
  501. data.axis.x = data.axis.x + flip.width()/2;
  502. this.zoom('scroll', data.scrollPos);
  503. }
  504. },
  505. _eZoom: function() {
  506. var flipPos,
  507. data = this.data().zoom,
  508. flip = data.opts.flipbook,
  509. view = flip.turn('view');
  510. for (var p = 0; p<view.length; p++) {
  511. if (view[p])
  512. this.trigger('zoom.resize',
  513. [data.scale, view[p], flip.data().pageObjs[view[p]]]
  514. );
  515. }
  516. },
  517. _eStart: function(event, pageObj) {
  518. if (this.zoom('value')!=1) {
  519. event.preventDefault();
  520. }
  521. },
  522. _eTurning: function(event, page, view) {
  523. var that = this,
  524. zoom = this.zoom('value'),
  525. data = this.data().zoom,
  526. flip = data.opts.flipbook;
  527. data.page = flip.turn('page');
  528. if (zoom!=1) {
  529. for (var p = 0; p<view.length; p++) {
  530. if (view[p])
  531. this.trigger('zoom.resize',
  532. [zoom, view[p], flip.data().pageObjs[view[p]]]
  533. );
  534. }
  535. setTimeout(function() {
  536. that.zoom('resize');
  537. }, 0);
  538. }
  539. },
  540. _eTurned: function (event, page) {
  541. if (this.zoom('value')!=1) {
  542. var that = this,
  543. data = this.data().zoom,
  544. flip = data.opts.flipbook;
  545. if (page>data.page)
  546. this.zoom('scroll',
  547. point2D(0, data.scrollPos.y), false, true);
  548. else if (page<data.page)
  549. this.zoom('scroll',
  550. point2D(flip.width(), data.scrollPos.y), false, true);
  551. }
  552. },
  553. _ePressed: function() {
  554. var data = $(this).data().zoom;
  555. data.draggingCorner = true;
  556. },
  557. _eReleased: function() {
  558. var data = $(this).data().zoom;
  559. setTimeout(function() {
  560. data.draggingCorner = false;
  561. }, 1);
  562. },
  563. _eMouseDown: function(event) {
  564. var data = $(this).data().zoom;
  565. data.draggingCur = ($.isTouch) ?
  566. point2D(
  567. event.originalEvent.touches[0].pageX,
  568. event.originalEvent.touches[0].pageY
  569. )
  570. :
  571. point2D(event.pageX, event.pageY);
  572. return false;
  573. },
  574. _eMouseMove: function(event) {
  575. var data = $(this).data().zoom;
  576. if (data.draggingCur) {
  577. data.dragging = true;
  578. var cur = ($.isTouch) ?
  579. point2D(
  580. event.originalEvent.touches[0].pageX,
  581. event.originalEvent.touches[0].pageY
  582. )
  583. :
  584. point2D(event.pageX, event.pageY),
  585. motion = point2D(
  586. cur.x- data.draggingCur.x,
  587. cur.y-data.draggingCur.y
  588. );
  589. $(this).zoom('scroll',
  590. point2D(
  591. data.scrollPos.x-motion.x,
  592. data.scrollPos.y-motion.y
  593. ), true
  594. );
  595. data.draggingCur = cur;
  596. return false;
  597. }
  598. },
  599. _eMouseUp: function(event) {
  600. var data = $(this).data().zoom;
  601. if (data.dragging) {
  602. $(this).zoom('scroll', data.scrollPos);
  603. }
  604. data.draggingCur = null;
  605. setTimeout(function() {
  606. data.dragging = false;
  607. }, 1);
  608. },
  609. _eMouseWheel: function(event, delta, deltaX, deltaY) {
  610. var data = $(this).data().zoom,
  611. cur = point2D(
  612. data.scrollPos.x + deltaX*10,
  613. data.scrollPos.y - deltaY*10
  614. );
  615. $(this).zoom('scroll', cur, false, true);
  616. },
  617. _eTouchStart: function(event, page) {
  618. var data = $(this).data().zoom,
  619. flip = data.opts.flipbook,
  620. finger = point2D(
  621. event.originalEvent.touches[0].pageX,
  622. event.originalEvent.touches[0].pageY
  623. );
  624. data.touch = {};
  625. data.touch.initial = finger;
  626. data.touch.last = finger;
  627. data.touch.timestamp = (new Date()).getTime();
  628. data.touch.speed = point2D(0, 0);
  629. },
  630. _eTouchMove: function(event) {
  631. var data = $(this).data().zoom,
  632. zoom = $(this).zoom('value'),
  633. flip = data.opts.flipbook,
  634. time = (new Date()).getTime(),
  635. finger = point2D(
  636. event.originalEvent.touches[0].pageX,
  637. event.originalEvent.touches[0].pageY
  638. );
  639. if (data.touch && zoom==1 && !flip.data().mouseAction) {
  640. data.touch.motion = point2D(
  641. finger.x-data.touch.last.x,
  642. finger.y-data.touch.last.y);
  643. data.touch.speed.x = (data.touch.speed.x===0) ?
  644. data.touch.motion.x / (time-data.touch.timestamp) :
  645. (data.touch.speed.x + (data.touch.motion.x / (time-data.touch.timestamp)))/2;
  646. data.touch.last = finger;
  647. data.touch.timestamp = time;
  648. }
  649. },
  650. _eTouchEnd: function(event) {
  651. var data = $(this).data().zoom;
  652. if (data.touch && $(this).zoom('value')==1) {
  653. var y = Math.abs(data.touch.initial.y - data.touch.last.y);
  654. if (y<50 && (data.touch.speed.x<-1 || data.touch.last.x-data.touch.initial.x<-100)) {
  655. this.trigger('zoom.swipeLeft');
  656. } else if(y<50 && (data.touch.speed.x>1 || data.touch.last.x-data.touch.initial.x>100)){
  657. this.trigger('zoom.swipeRight');
  658. }
  659. }
  660. },
  661. _eDestroying: function() {
  662. var that = this,
  663. data = this.data().zoom,
  664. flip = data.opts.flipbook,
  665. events = [
  666. 'tap',
  667. 'doubleTap',
  668. 'resize',
  669. 'zoomIn',
  670. 'zoomOut',
  671. 'swipeLeft',
  672. 'swipeRight'
  673. ];
  674. this.zoom('zoomOut', 0);
  675. $.each(events, function(index, eventName) {
  676. that.unbind('zoom.' + eventName);
  677. });
  678. for (var eventName in data.flipbookEvents) {
  679. if (Object.prototype.hasOwnProperty.call(data.flipbookEvents, eventName)) {
  680. flip.unbind(eventName, data.flipbookEvents[eventName]);
  681. }
  682. }
  683. flip.unbind('touchstart', data.eventTouchStart ).
  684. unbind('touchmove', data.eventTouchMove).
  685. unbind('touchend', data.eventTouchEnd);
  686. this.unbind('touchstart', zoomMethods._tap).
  687. unbind('click', zoomMethods._tap);
  688. data = null;
  689. this.data().zoom = null;
  690. }
  691. };
  692. function isPage(element, last) {
  693. if (element[0]==last[0])
  694. return false;
  695. if (element.attr('page'))
  696. return true;
  697. return (element.parent()[0]) ?
  698. isPage(element.parent(), last)
  699. :
  700. false;
  701. }
  702. function error(message) {
  703. function TurnJsError(message) {
  704. this.name = "TurnJsError";
  705. this.message = message;
  706. }
  707. TurnJsError.prototype = new Error();
  708. TurnJsError.prototype.constructor = TurnJsError;
  709. return new TurnJsError(message);
  710. }
  711. function translate(x, y, use3d) {
  712. return (has3d && use3d) ? ' translate3d(' + x + 'px,' + y + 'px, 0px) '
  713. : ' translate(' + x + 'px, ' + y + 'px) ';
  714. }
  715. function scale(v, use3d) {
  716. return (has3d && use3d) ? ' scale3d(' + v + ', ' + v + ', 1) '
  717. : ' scale(' + v + ') ';
  718. }
  719. function point2D(x, y) {
  720. return {x: x, y: y};
  721. }
  722. function bind(func, context) {
  723. return function() {
  724. return func.apply(context, arguments);
  725. };
  726. }
  727. $.extend($.fn, {
  728. zoom: function() {
  729. var args = arguments;
  730. if (!args[0] || typeof(args[0])=='object')
  731. return zoomMethods.init.apply($(this[0]), args);
  732. else if (zoomMethods[args[0]])
  733. return zoomMethods[args[0]].apply($(this[0]), Array.prototype.slice.call(args, 1));
  734. else
  735. throw error(args[0] + ' is not a method');
  736. }
  737. });
  738. })(jQuery);