zoom.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. import { getWindow } from 'ssr-window';
  2. import { elementChildren, elementOffset, elementParents, getTranslate } from '../../shared/utils.js';
  3. export default function Zoom({
  4. swiper,
  5. extendParams,
  6. on,
  7. emit
  8. }) {
  9. const window = getWindow();
  10. extendParams({
  11. zoom: {
  12. enabled: false,
  13. maxRatio: 3,
  14. minRatio: 1,
  15. toggle: true,
  16. containerClass: 'swiper-zoom-container',
  17. zoomedSlideClass: 'swiper-slide-zoomed'
  18. }
  19. });
  20. swiper.zoom = {
  21. enabled: false
  22. };
  23. let currentScale = 1;
  24. let isScaling = false;
  25. let fakeGestureTouched;
  26. let fakeGestureMoved;
  27. const evCache = [];
  28. const gesture = {
  29. originX: 0,
  30. originY: 0,
  31. slideEl: undefined,
  32. slideWidth: undefined,
  33. slideHeight: undefined,
  34. imageEl: undefined,
  35. imageWrapEl: undefined,
  36. maxRatio: 3
  37. };
  38. const image = {
  39. isTouched: undefined,
  40. isMoved: undefined,
  41. currentX: undefined,
  42. currentY: undefined,
  43. minX: undefined,
  44. minY: undefined,
  45. maxX: undefined,
  46. maxY: undefined,
  47. width: undefined,
  48. height: undefined,
  49. startX: undefined,
  50. startY: undefined,
  51. touchesStart: {},
  52. touchesCurrent: {}
  53. };
  54. const velocity = {
  55. x: undefined,
  56. y: undefined,
  57. prevPositionX: undefined,
  58. prevPositionY: undefined,
  59. prevTime: undefined
  60. };
  61. let scale = 1;
  62. Object.defineProperty(swiper.zoom, 'scale', {
  63. get() {
  64. return scale;
  65. },
  66. set(value) {
  67. if (scale !== value) {
  68. const imageEl = gesture.imageEl;
  69. const slideEl = gesture.slideEl;
  70. emit('zoomChange', value, imageEl, slideEl);
  71. }
  72. scale = value;
  73. }
  74. });
  75. function getDistanceBetweenTouches() {
  76. if (evCache.length < 2) return 1;
  77. const x1 = evCache[0].pageX;
  78. const y1 = evCache[0].pageY;
  79. const x2 = evCache[1].pageX;
  80. const y2 = evCache[1].pageY;
  81. const distance = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
  82. return distance;
  83. }
  84. function getScaleOrigin() {
  85. if (evCache.length < 2) return {
  86. x: null,
  87. y: null
  88. };
  89. const box = gesture.imageEl.getBoundingClientRect();
  90. return [(evCache[0].pageX + (evCache[1].pageX - evCache[0].pageX) / 2 - box.x) / currentScale, (evCache[0].pageY + (evCache[1].pageY - evCache[0].pageY) / 2 - box.y) / currentScale];
  91. }
  92. function getSlideSelector() {
  93. return swiper.isElement ? `swiper-slide` : `.${swiper.params.slideClass}`;
  94. }
  95. function eventWithinSlide(e) {
  96. const slideSelector = getSlideSelector();
  97. if (e.target.matches(slideSelector)) return true;
  98. if (swiper.slides.filter(slideEl => slideEl.contains(e.target)).length > 0) return true;
  99. return false;
  100. }
  101. function eventWithinZoomContainer(e) {
  102. const selector = `.${swiper.params.zoom.containerClass}`;
  103. if (e.target.matches(selector)) return true;
  104. if ([...swiper.el.querySelectorAll(selector)].filter(containerEl => containerEl.contains(e.target)).length > 0) return true;
  105. return false;
  106. }
  107. // Events
  108. function onGestureStart(e) {
  109. if (e.pointerType === 'mouse') {
  110. evCache.splice(0, evCache.length);
  111. }
  112. if (!eventWithinSlide(e)) return;
  113. const params = swiper.params.zoom;
  114. fakeGestureTouched = false;
  115. fakeGestureMoved = false;
  116. evCache.push(e);
  117. if (evCache.length < 2) {
  118. return;
  119. }
  120. fakeGestureTouched = true;
  121. gesture.scaleStart = getDistanceBetweenTouches();
  122. if (!gesture.slideEl) {
  123. gesture.slideEl = e.target.closest(`.${swiper.params.slideClass}, swiper-slide`);
  124. if (!gesture.slideEl) gesture.slideEl = swiper.slides[swiper.activeIndex];
  125. let imageEl = gesture.slideEl.querySelector(`.${params.containerClass}`);
  126. if (imageEl) {
  127. imageEl = imageEl.querySelectorAll('picture, img, svg, canvas, .swiper-zoom-target')[0];
  128. }
  129. gesture.imageEl = imageEl;
  130. if (imageEl) {
  131. gesture.imageWrapEl = elementParents(gesture.imageEl, `.${params.containerClass}`)[0];
  132. } else {
  133. gesture.imageWrapEl = undefined;
  134. }
  135. if (!gesture.imageWrapEl) {
  136. gesture.imageEl = undefined;
  137. return;
  138. }
  139. gesture.maxRatio = gesture.imageWrapEl.getAttribute('data-swiper-zoom') || params.maxRatio;
  140. }
  141. if (gesture.imageEl) {
  142. const [originX, originY] = getScaleOrigin();
  143. gesture.originX = originX;
  144. gesture.originY = originY;
  145. gesture.imageEl.style.transitionDuration = '0ms';
  146. }
  147. isScaling = true;
  148. }
  149. function onGestureChange(e) {
  150. if (!eventWithinSlide(e)) return;
  151. const params = swiper.params.zoom;
  152. const zoom = swiper.zoom;
  153. const pointerIndex = evCache.findIndex(cachedEv => cachedEv.pointerId === e.pointerId);
  154. if (pointerIndex >= 0) evCache[pointerIndex] = e;
  155. if (evCache.length < 2) {
  156. return;
  157. }
  158. fakeGestureMoved = true;
  159. gesture.scaleMove = getDistanceBetweenTouches();
  160. if (!gesture.imageEl) {
  161. return;
  162. }
  163. zoom.scale = gesture.scaleMove / gesture.scaleStart * currentScale;
  164. if (zoom.scale > gesture.maxRatio) {
  165. zoom.scale = gesture.maxRatio - 1 + (zoom.scale - gesture.maxRatio + 1) ** 0.5;
  166. }
  167. if (zoom.scale < params.minRatio) {
  168. zoom.scale = params.minRatio + 1 - (params.minRatio - zoom.scale + 1) ** 0.5;
  169. }
  170. gesture.imageEl.style.transform = `translate3d(0,0,0) scale(${zoom.scale})`;
  171. }
  172. function onGestureEnd(e) {
  173. if (!eventWithinSlide(e)) return;
  174. if (e.pointerType === 'mouse' && e.type === 'pointerout') return;
  175. const params = swiper.params.zoom;
  176. const zoom = swiper.zoom;
  177. const pointerIndex = evCache.findIndex(cachedEv => cachedEv.pointerId === e.pointerId);
  178. if (pointerIndex >= 0) evCache.splice(pointerIndex, 1);
  179. if (!fakeGestureTouched || !fakeGestureMoved) {
  180. return;
  181. }
  182. fakeGestureTouched = false;
  183. fakeGestureMoved = false;
  184. if (!gesture.imageEl) return;
  185. zoom.scale = Math.max(Math.min(zoom.scale, gesture.maxRatio), params.minRatio);
  186. gesture.imageEl.style.transitionDuration = `${swiper.params.speed}ms`;
  187. gesture.imageEl.style.transform = `translate3d(0,0,0) scale(${zoom.scale})`;
  188. currentScale = zoom.scale;
  189. isScaling = false;
  190. if (zoom.scale > 1 && gesture.slideEl) {
  191. gesture.slideEl.classList.add(`${params.zoomedSlideClass}`);
  192. } else if (zoom.scale <= 1 && gesture.slideEl) {
  193. gesture.slideEl.classList.remove(`${params.zoomedSlideClass}`);
  194. }
  195. if (zoom.scale === 1) {
  196. gesture.originX = 0;
  197. gesture.originY = 0;
  198. gesture.slideEl = undefined;
  199. }
  200. }
  201. function onTouchStart(e) {
  202. const device = swiper.device;
  203. if (!gesture.imageEl) return;
  204. if (image.isTouched) return;
  205. if (device.android && e.cancelable) e.preventDefault();
  206. image.isTouched = true;
  207. const event = evCache.length > 0 ? evCache[0] : e;
  208. image.touchesStart.x = event.pageX;
  209. image.touchesStart.y = event.pageY;
  210. }
  211. function onTouchMove(e) {
  212. if (!eventWithinSlide(e) || !eventWithinZoomContainer(e)) return;
  213. const zoom = swiper.zoom;
  214. if (!gesture.imageEl) return;
  215. if (!image.isTouched || !gesture.slideEl) return;
  216. if (!image.isMoved) {
  217. image.width = gesture.imageEl.offsetWidth;
  218. image.height = gesture.imageEl.offsetHeight;
  219. image.startX = getTranslate(gesture.imageWrapEl, 'x') || 0;
  220. image.startY = getTranslate(gesture.imageWrapEl, 'y') || 0;
  221. gesture.slideWidth = gesture.slideEl.offsetWidth;
  222. gesture.slideHeight = gesture.slideEl.offsetHeight;
  223. gesture.imageWrapEl.style.transitionDuration = '0ms';
  224. }
  225. // Define if we need image drag
  226. const scaledWidth = image.width * zoom.scale;
  227. const scaledHeight = image.height * zoom.scale;
  228. if (scaledWidth < gesture.slideWidth && scaledHeight < gesture.slideHeight) return;
  229. image.minX = Math.min(gesture.slideWidth / 2 - scaledWidth / 2, 0);
  230. image.maxX = -image.minX;
  231. image.minY = Math.min(gesture.slideHeight / 2 - scaledHeight / 2, 0);
  232. image.maxY = -image.minY;
  233. image.touchesCurrent.x = evCache.length > 0 ? evCache[0].pageX : e.pageX;
  234. image.touchesCurrent.y = evCache.length > 0 ? evCache[0].pageY : e.pageY;
  235. const touchesDiff = Math.max(Math.abs(image.touchesCurrent.x - image.touchesStart.x), Math.abs(image.touchesCurrent.y - image.touchesStart.y));
  236. if (touchesDiff > 5) {
  237. swiper.allowClick = false;
  238. }
  239. if (!image.isMoved && !isScaling) {
  240. if (swiper.isHorizontal() && (Math.floor(image.minX) === Math.floor(image.startX) && image.touchesCurrent.x < image.touchesStart.x || Math.floor(image.maxX) === Math.floor(image.startX) && image.touchesCurrent.x > image.touchesStart.x)) {
  241. image.isTouched = false;
  242. return;
  243. }
  244. if (!swiper.isHorizontal() && (Math.floor(image.minY) === Math.floor(image.startY) && image.touchesCurrent.y < image.touchesStart.y || Math.floor(image.maxY) === Math.floor(image.startY) && image.touchesCurrent.y > image.touchesStart.y)) {
  245. image.isTouched = false;
  246. return;
  247. }
  248. }
  249. if (e.cancelable) {
  250. e.preventDefault();
  251. }
  252. e.stopPropagation();
  253. image.isMoved = true;
  254. const scaleRatio = (zoom.scale - currentScale) / (gesture.maxRatio - swiper.params.zoom.minRatio);
  255. const {
  256. originX,
  257. originY
  258. } = gesture;
  259. image.currentX = image.touchesCurrent.x - image.touchesStart.x + image.startX + scaleRatio * (image.width - originX * 2);
  260. image.currentY = image.touchesCurrent.y - image.touchesStart.y + image.startY + scaleRatio * (image.height - originY * 2);
  261. if (image.currentX < image.minX) {
  262. image.currentX = image.minX + 1 - (image.minX - image.currentX + 1) ** 0.8;
  263. }
  264. if (image.currentX > image.maxX) {
  265. image.currentX = image.maxX - 1 + (image.currentX - image.maxX + 1) ** 0.8;
  266. }
  267. if (image.currentY < image.minY) {
  268. image.currentY = image.minY + 1 - (image.minY - image.currentY + 1) ** 0.8;
  269. }
  270. if (image.currentY > image.maxY) {
  271. image.currentY = image.maxY - 1 + (image.currentY - image.maxY + 1) ** 0.8;
  272. }
  273. // Velocity
  274. if (!velocity.prevPositionX) velocity.prevPositionX = image.touchesCurrent.x;
  275. if (!velocity.prevPositionY) velocity.prevPositionY = image.touchesCurrent.y;
  276. if (!velocity.prevTime) velocity.prevTime = Date.now();
  277. velocity.x = (image.touchesCurrent.x - velocity.prevPositionX) / (Date.now() - velocity.prevTime) / 2;
  278. velocity.y = (image.touchesCurrent.y - velocity.prevPositionY) / (Date.now() - velocity.prevTime) / 2;
  279. if (Math.abs(image.touchesCurrent.x - velocity.prevPositionX) < 2) velocity.x = 0;
  280. if (Math.abs(image.touchesCurrent.y - velocity.prevPositionY) < 2) velocity.y = 0;
  281. velocity.prevPositionX = image.touchesCurrent.x;
  282. velocity.prevPositionY = image.touchesCurrent.y;
  283. velocity.prevTime = Date.now();
  284. gesture.imageWrapEl.style.transform = `translate3d(${image.currentX}px, ${image.currentY}px,0)`;
  285. }
  286. function onTouchEnd() {
  287. const zoom = swiper.zoom;
  288. if (!gesture.imageEl) return;
  289. if (!image.isTouched || !image.isMoved) {
  290. image.isTouched = false;
  291. image.isMoved = false;
  292. return;
  293. }
  294. image.isTouched = false;
  295. image.isMoved = false;
  296. let momentumDurationX = 300;
  297. let momentumDurationY = 300;
  298. const momentumDistanceX = velocity.x * momentumDurationX;
  299. const newPositionX = image.currentX + momentumDistanceX;
  300. const momentumDistanceY = velocity.y * momentumDurationY;
  301. const newPositionY = image.currentY + momentumDistanceY;
  302. // Fix duration
  303. if (velocity.x !== 0) momentumDurationX = Math.abs((newPositionX - image.currentX) / velocity.x);
  304. if (velocity.y !== 0) momentumDurationY = Math.abs((newPositionY - image.currentY) / velocity.y);
  305. const momentumDuration = Math.max(momentumDurationX, momentumDurationY);
  306. image.currentX = newPositionX;
  307. image.currentY = newPositionY;
  308. // Define if we need image drag
  309. const scaledWidth = image.width * zoom.scale;
  310. const scaledHeight = image.height * zoom.scale;
  311. image.minX = Math.min(gesture.slideWidth / 2 - scaledWidth / 2, 0);
  312. image.maxX = -image.minX;
  313. image.minY = Math.min(gesture.slideHeight / 2 - scaledHeight / 2, 0);
  314. image.maxY = -image.minY;
  315. image.currentX = Math.max(Math.min(image.currentX, image.maxX), image.minX);
  316. image.currentY = Math.max(Math.min(image.currentY, image.maxY), image.minY);
  317. gesture.imageWrapEl.style.transitionDuration = `${momentumDuration}ms`;
  318. gesture.imageWrapEl.style.transform = `translate3d(${image.currentX}px, ${image.currentY}px,0)`;
  319. }
  320. function onTransitionEnd() {
  321. const zoom = swiper.zoom;
  322. if (gesture.slideEl && swiper.activeIndex !== swiper.slides.indexOf(gesture.slideEl)) {
  323. if (gesture.imageEl) {
  324. gesture.imageEl.style.transform = 'translate3d(0,0,0) scale(1)';
  325. }
  326. if (gesture.imageWrapEl) {
  327. gesture.imageWrapEl.style.transform = 'translate3d(0,0,0)';
  328. }
  329. gesture.slideEl.classList.remove(`${swiper.params.zoom.zoomedSlideClass}`);
  330. zoom.scale = 1;
  331. currentScale = 1;
  332. gesture.slideEl = undefined;
  333. gesture.imageEl = undefined;
  334. gesture.imageWrapEl = undefined;
  335. gesture.originX = 0;
  336. gesture.originY = 0;
  337. }
  338. }
  339. function zoomIn(e) {
  340. const zoom = swiper.zoom;
  341. const params = swiper.params.zoom;
  342. if (!gesture.slideEl) {
  343. if (e && e.target) {
  344. gesture.slideEl = e.target.closest(`.${swiper.params.slideClass}, swiper-slide`);
  345. }
  346. if (!gesture.slideEl) {
  347. if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {
  348. gesture.slideEl = elementChildren(swiper.slidesEl, `.${swiper.params.slideActiveClass}`)[0];
  349. } else {
  350. gesture.slideEl = swiper.slides[swiper.activeIndex];
  351. }
  352. }
  353. let imageEl = gesture.slideEl.querySelector(`.${params.containerClass}`);
  354. if (imageEl) {
  355. imageEl = imageEl.querySelectorAll('picture, img, svg, canvas, .swiper-zoom-target')[0];
  356. }
  357. gesture.imageEl = imageEl;
  358. if (imageEl) {
  359. gesture.imageWrapEl = elementParents(gesture.imageEl, `.${params.containerClass}`)[0];
  360. } else {
  361. gesture.imageWrapEl = undefined;
  362. }
  363. }
  364. if (!gesture.imageEl || !gesture.imageWrapEl) return;
  365. if (swiper.params.cssMode) {
  366. swiper.wrapperEl.style.overflow = 'hidden';
  367. swiper.wrapperEl.style.touchAction = 'none';
  368. }
  369. gesture.slideEl.classList.add(`${params.zoomedSlideClass}`);
  370. let touchX;
  371. let touchY;
  372. let offsetX;
  373. let offsetY;
  374. let diffX;
  375. let diffY;
  376. let translateX;
  377. let translateY;
  378. let imageWidth;
  379. let imageHeight;
  380. let scaledWidth;
  381. let scaledHeight;
  382. let translateMinX;
  383. let translateMinY;
  384. let translateMaxX;
  385. let translateMaxY;
  386. let slideWidth;
  387. let slideHeight;
  388. if (typeof image.touchesStart.x === 'undefined' && e) {
  389. touchX = e.pageX;
  390. touchY = e.pageY;
  391. } else {
  392. touchX = image.touchesStart.x;
  393. touchY = image.touchesStart.y;
  394. }
  395. const forceZoomRatio = typeof e === 'number' ? e : null;
  396. if (currentScale === 1 && forceZoomRatio) {
  397. touchX = undefined;
  398. touchY = undefined;
  399. }
  400. zoom.scale = forceZoomRatio || gesture.imageWrapEl.getAttribute('data-swiper-zoom') || params.maxRatio;
  401. currentScale = forceZoomRatio || gesture.imageWrapEl.getAttribute('data-swiper-zoom') || params.maxRatio;
  402. if (e && !(currentScale === 1 && forceZoomRatio)) {
  403. slideWidth = gesture.slideEl.offsetWidth;
  404. slideHeight = gesture.slideEl.offsetHeight;
  405. offsetX = elementOffset(gesture.slideEl).left + window.scrollX;
  406. offsetY = elementOffset(gesture.slideEl).top + window.scrollY;
  407. diffX = offsetX + slideWidth / 2 - touchX;
  408. diffY = offsetY + slideHeight / 2 - touchY;
  409. imageWidth = gesture.imageEl.offsetWidth;
  410. imageHeight = gesture.imageEl.offsetHeight;
  411. scaledWidth = imageWidth * zoom.scale;
  412. scaledHeight = imageHeight * zoom.scale;
  413. translateMinX = Math.min(slideWidth / 2 - scaledWidth / 2, 0);
  414. translateMinY = Math.min(slideHeight / 2 - scaledHeight / 2, 0);
  415. translateMaxX = -translateMinX;
  416. translateMaxY = -translateMinY;
  417. translateX = diffX * zoom.scale;
  418. translateY = diffY * zoom.scale;
  419. if (translateX < translateMinX) {
  420. translateX = translateMinX;
  421. }
  422. if (translateX > translateMaxX) {
  423. translateX = translateMaxX;
  424. }
  425. if (translateY < translateMinY) {
  426. translateY = translateMinY;
  427. }
  428. if (translateY > translateMaxY) {
  429. translateY = translateMaxY;
  430. }
  431. } else {
  432. translateX = 0;
  433. translateY = 0;
  434. }
  435. if (forceZoomRatio && zoom.scale === 1) {
  436. gesture.originX = 0;
  437. gesture.originY = 0;
  438. }
  439. gesture.imageWrapEl.style.transitionDuration = '300ms';
  440. gesture.imageWrapEl.style.transform = `translate3d(${translateX}px, ${translateY}px,0)`;
  441. gesture.imageEl.style.transitionDuration = '300ms';
  442. gesture.imageEl.style.transform = `translate3d(0,0,0) scale(${zoom.scale})`;
  443. }
  444. function zoomOut() {
  445. const zoom = swiper.zoom;
  446. const params = swiper.params.zoom;
  447. if (!gesture.slideEl) {
  448. if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {
  449. gesture.slideEl = elementChildren(swiper.slidesEl, `.${swiper.params.slideActiveClass}`)[0];
  450. } else {
  451. gesture.slideEl = swiper.slides[swiper.activeIndex];
  452. }
  453. let imageEl = gesture.slideEl.querySelector(`.${params.containerClass}`);
  454. if (imageEl) {
  455. imageEl = imageEl.querySelectorAll('picture, img, svg, canvas, .swiper-zoom-target')[0];
  456. }
  457. gesture.imageEl = imageEl;
  458. if (imageEl) {
  459. gesture.imageWrapEl = elementParents(gesture.imageEl, `.${params.containerClass}`)[0];
  460. } else {
  461. gesture.imageWrapEl = undefined;
  462. }
  463. }
  464. if (!gesture.imageEl || !gesture.imageWrapEl) return;
  465. if (swiper.params.cssMode) {
  466. swiper.wrapperEl.style.overflow = '';
  467. swiper.wrapperEl.style.touchAction = '';
  468. }
  469. zoom.scale = 1;
  470. currentScale = 1;
  471. gesture.imageWrapEl.style.transitionDuration = '300ms';
  472. gesture.imageWrapEl.style.transform = 'translate3d(0,0,0)';
  473. gesture.imageEl.style.transitionDuration = '300ms';
  474. gesture.imageEl.style.transform = 'translate3d(0,0,0) scale(1)';
  475. gesture.slideEl.classList.remove(`${params.zoomedSlideClass}`);
  476. gesture.slideEl = undefined;
  477. gesture.originX = 0;
  478. gesture.originY = 0;
  479. }
  480. // Toggle Zoom
  481. function zoomToggle(e) {
  482. const zoom = swiper.zoom;
  483. if (zoom.scale && zoom.scale !== 1) {
  484. // Zoom Out
  485. zoomOut();
  486. } else {
  487. // Zoom In
  488. zoomIn(e);
  489. }
  490. }
  491. function getListeners() {
  492. const passiveListener = swiper.params.passiveListeners ? {
  493. passive: true,
  494. capture: false
  495. } : false;
  496. const activeListenerWithCapture = swiper.params.passiveListeners ? {
  497. passive: false,
  498. capture: true
  499. } : true;
  500. return {
  501. passiveListener,
  502. activeListenerWithCapture
  503. };
  504. }
  505. // Attach/Detach Events
  506. function enable() {
  507. const zoom = swiper.zoom;
  508. if (zoom.enabled) return;
  509. zoom.enabled = true;
  510. const {
  511. passiveListener,
  512. activeListenerWithCapture
  513. } = getListeners();
  514. // Scale image
  515. swiper.wrapperEl.addEventListener('pointerdown', onGestureStart, passiveListener);
  516. swiper.wrapperEl.addEventListener('pointermove', onGestureChange, activeListenerWithCapture);
  517. ['pointerup', 'pointercancel', 'pointerout'].forEach(eventName => {
  518. swiper.wrapperEl.addEventListener(eventName, onGestureEnd, passiveListener);
  519. });
  520. // Move image
  521. swiper.wrapperEl.addEventListener('pointermove', onTouchMove, activeListenerWithCapture);
  522. }
  523. function disable() {
  524. const zoom = swiper.zoom;
  525. if (!zoom.enabled) return;
  526. zoom.enabled = false;
  527. const {
  528. passiveListener,
  529. activeListenerWithCapture
  530. } = getListeners();
  531. // Scale image
  532. swiper.wrapperEl.removeEventListener('pointerdown', onGestureStart, passiveListener);
  533. swiper.wrapperEl.removeEventListener('pointermove', onGestureChange, activeListenerWithCapture);
  534. ['pointerup', 'pointercancel', 'pointerout'].forEach(eventName => {
  535. swiper.wrapperEl.removeEventListener(eventName, onGestureEnd, passiveListener);
  536. });
  537. // Move image
  538. swiper.wrapperEl.removeEventListener('pointermove', onTouchMove, activeListenerWithCapture);
  539. }
  540. on('init', () => {
  541. if (swiper.params.zoom.enabled) {
  542. enable();
  543. }
  544. });
  545. on('destroy', () => {
  546. disable();
  547. });
  548. on('touchStart', (_s, e) => {
  549. if (!swiper.zoom.enabled) return;
  550. onTouchStart(e);
  551. });
  552. on('touchEnd', (_s, e) => {
  553. if (!swiper.zoom.enabled) return;
  554. onTouchEnd(e);
  555. });
  556. on('doubleTap', (_s, e) => {
  557. if (!swiper.animating && swiper.params.zoom.enabled && swiper.zoom.enabled && swiper.params.zoom.toggle) {
  558. zoomToggle(e);
  559. }
  560. });
  561. on('transitionEnd', () => {
  562. if (swiper.zoom.enabled && swiper.params.zoom.enabled) {
  563. onTransitionEnd();
  564. }
  565. });
  566. on('slideChange', () => {
  567. if (swiper.zoom.enabled && swiper.params.zoom.enabled && swiper.params.cssMode) {
  568. onTransitionEnd();
  569. }
  570. });
  571. Object.assign(swiper.zoom, {
  572. enable,
  573. disable,
  574. in: zoomIn,
  575. out: zoomOut,
  576. toggle: zoomToggle
  577. });
  578. }