zoom.mjs 22 KB

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