vanilla-js-wheel-zoom

Image resizing using mouse wheel + drag scrollable image (as well as any HTML content)

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/420842/927891/vanilla-js-wheel-zoom.js

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined'
  3. ? (module.exports = factory())
  4. : typeof define === 'function' && define.amd
  5. ? define(factory)
  6. : ((global =
  7. typeof globalThis !== 'undefined' ? globalThis : global || self),
  8. (global.WZoom = factory()));
  9. })(this, function () {
  10. 'use strict';
  11.  
  12. /**
  13. * Get element position (with support old browsers)
  14. * @param {Element} element
  15. * @returns {{top: number, left: number}}
  16. */
  17. function getElementPosition(element) {
  18. var box = element.getBoundingClientRect();
  19. var _document = document,
  20. body = _document.body,
  21. documentElement = _document.documentElement;
  22. var scrollTop =
  23. window.pageYOffset || documentElement.scrollTop || body.scrollTop;
  24. var scrollLeft =
  25. window.pageXOffset || documentElement.scrollLeft || body.scrollLeft;
  26. var clientTop = documentElement.clientTop || body.clientTop || 0;
  27. var clientLeft = documentElement.clientLeft || body.clientLeft || 0;
  28. var top = box.top + scrollTop - clientTop;
  29. var left = box.left + scrollLeft - clientLeft;
  30. return {
  31. top: top,
  32. left: left,
  33. };
  34. }
  35. /**
  36. * Universal alternative to Object.assign()
  37. * @param {Object} destination
  38. * @param {Object} source
  39. * @returns {Object}
  40. */
  41.  
  42. function extendObject(destination, source) {
  43. if (destination && source) {
  44. for (var key in source) {
  45. if (source.hasOwnProperty(key)) {
  46. destination[key] = source[key];
  47. }
  48. }
  49. }
  50.  
  51. return destination;
  52. }
  53. /**
  54. * @param target
  55. * @param type
  56. * @param listener
  57. * @param options
  58. */
  59.  
  60. function on(target, type, listener) {
  61. var options =
  62. arguments.length > 3 && arguments[3] !== undefined
  63. ? arguments[3]
  64. : false;
  65. target.addEventListener(type, listener, options);
  66. }
  67. /**
  68. * @param target
  69. * @param type
  70. * @param listener
  71. * @param options
  72. */
  73.  
  74. function off(target, type, listener) {
  75. var options =
  76. arguments.length > 3 && arguments[3] !== undefined
  77. ? arguments[3]
  78. : false;
  79. target.removeEventListener(type, listener, options);
  80. }
  81. function isTouch() {
  82. return (
  83. 'ontouchstart' in window ||
  84. navigator.MaxTouchPoints > 0 ||
  85. navigator.msMaxTouchPoints > 0
  86. );
  87. }
  88. function eventClientX(event) {
  89. return event.type === 'wheel' ||
  90. event.type === 'mousedown' ||
  91. event.type === 'mousemove' ||
  92. event.type === 'mouseup'
  93. ? event.clientX
  94. : event.changedTouches[0].clientX;
  95. }
  96. function eventClientY(event) {
  97. return event.type === 'wheel' ||
  98. event.type === 'mousedown' ||
  99. event.type === 'mousemove' ||
  100. event.type === 'mouseup'
  101. ? event.clientY
  102. : event.changedTouches[0].clientY;
  103. }
  104.  
  105. /**
  106. * @class DragScrollable
  107. * @param {Object} windowObject
  108. * @param {Object} contentObject
  109. * @param {Object} options
  110. * @constructor
  111. */
  112.  
  113. function DragScrollable(windowObject, contentObject) {
  114. var options =
  115. arguments.length > 2 && arguments[2] !== undefined
  116. ? arguments[2]
  117. : {};
  118. this._dropHandler = this._dropHandler.bind(this);
  119. this._grabHandler = this._grabHandler.bind(this);
  120. this._moveHandler = this._moveHandler.bind(this);
  121. this.options = extendObject(
  122. {
  123. // smooth extinction moving element after set loose
  124. smoothExtinction: false,
  125. // callback triggered when grabbing an element
  126. onGrab: null,
  127. // callback triggered when moving an element
  128. onMove: null,
  129. // callback triggered when dropping an element
  130. onDrop: null,
  131. },
  132. options
  133. ); // check if we're using a touch screen
  134.  
  135. this.isTouch = isTouch(); // switch to touch events if using a touch screen
  136.  
  137. this.events = this.isTouch
  138. ? {
  139. grab: 'touchstart',
  140. move: 'touchmove',
  141. drop: 'touchend',
  142. }
  143. : {
  144. grab: 'mousedown',
  145. move: 'mousemove',
  146. drop: 'mouseup',
  147. }; // for the touch screen we set the parameter forcibly
  148.  
  149. this.events.options = this.isTouch
  150. ? {
  151. passive: false,
  152. }
  153. : false;
  154. this.window = windowObject;
  155. this.content = contentObject;
  156. on(
  157. this.content.$element,
  158. this.events.grab,
  159. this._grabHandler,
  160. this.events.options
  161. );
  162. }
  163.  
  164. DragScrollable.prototype = {
  165. constructor: DragScrollable,
  166. window: null,
  167. content: null,
  168. isTouch: false,
  169. isGrab: false,
  170. events: null,
  171. moveTimer: null,
  172. options: {},
  173. coordinates: null,
  174. speed: null,
  175. _grabHandler: function _grabHandler(event) {
  176. // if touch started (only one finger) or pressed left mouse button
  177. if (
  178. (this.isTouch && event.touches.length === 1) ||
  179. event.buttons === 1
  180. ) {
  181. event.preventDefault();
  182. this.isGrab = true;
  183. this.coordinates = {
  184. left: eventClientX(event),
  185. top: eventClientY(event),
  186. };
  187. this.speed = {
  188. x: 0,
  189. y: 0,
  190. };
  191. on(
  192. document,
  193. this.events.drop,
  194. this._dropHandler,
  195. this.events.options
  196. );
  197. on(
  198. document,
  199. this.events.move,
  200. this._moveHandler,
  201. this.events.options
  202. );
  203.  
  204. if (typeof this.options.onGrab === 'function') {
  205. this.options.onGrab();
  206. }
  207. }
  208. },
  209. _dropHandler: function _dropHandler(event) {
  210. event.preventDefault();
  211. this.isGrab = false; // if (this.options.smoothExtinction) {
  212. // _moveExtinction.call(this, 'scrollLeft', numberExtinction(this.speed.x));
  213. // _moveExtinction.call(this, 'scrollTop', numberExtinction(this.speed.y));
  214. // }
  215.  
  216. off(document, this.events.drop, this._dropHandler);
  217. off(document, this.events.move, this._moveHandler);
  218.  
  219. if (typeof this.options.onDrop === 'function') {
  220. this.options.onDrop();
  221. }
  222. },
  223. _moveHandler: function _moveHandler(event) {
  224. if (this.isTouch && event.touches.length > 1) return false;
  225. event.preventDefault();
  226. var window = this.window,
  227. content = this.content,
  228. speed = this.speed,
  229. coordinates = this.coordinates,
  230. options = this.options; // speed of change of the coordinate of the mouse cursor along the X/Y axis
  231.  
  232. speed.x = eventClientX(event) - coordinates.left;
  233. speed.y = eventClientY(event) - coordinates.top;
  234. clearTimeout(this.moveTimer); // reset speed data if cursor stops
  235.  
  236. this.moveTimer = setTimeout(function () {
  237. speed.x = 0;
  238. speed.y = 0;
  239. }, 50);
  240. var contentNewLeft = content.currentLeft + speed.x;
  241. var contentNewTop = content.currentTop + speed.y;
  242. var maxAvailableLeft =
  243. (content.currentWidth - window.originalWidth) / 2 +
  244. content.correctX;
  245. var maxAvailableTop =
  246. (content.currentHeight - window.originalHeight) / 2 +
  247. content.correctY; // if we do not go beyond the permissible boundaries of the window
  248.  
  249. if (Math.abs(contentNewLeft) <= maxAvailableLeft)
  250. content.currentLeft = contentNewLeft; // if we do not go beyond the permissible boundaries of the window
  251.  
  252. if (Math.abs(contentNewTop) <= maxAvailableTop)
  253. content.currentTop = contentNewTop;
  254.  
  255. _transform(content.$element, {
  256. left: content.currentLeft,
  257. top: content.currentTop,
  258. scale: content.currentScale,
  259. });
  260.  
  261. coordinates.left = eventClientX(event);
  262. coordinates.top = eventClientY(event);
  263.  
  264. if (typeof options.onMove === 'function') {
  265. options.onMove();
  266. }
  267. },
  268. destroy: function destroy() {
  269. off(
  270. this.content.$element,
  271. this.events.grab,
  272. this._grabHandler,
  273. this.events.options
  274. );
  275.  
  276. for (var key in this) {
  277. if (this.hasOwnProperty(key)) {
  278. this[key] = null;
  279. }
  280. }
  281. },
  282. };
  283.  
  284. function _transform($element, _ref) {
  285. var left = _ref.left,
  286. top = _ref.top,
  287. scale = _ref.scale;
  288. $element.style.transform = 'translate3d('
  289. .concat(left, 'px, ')
  290. .concat(top, 'px, 0px) scale(')
  291. .concat(scale, ')');
  292. } // function _moveExtinction(field, speedArray) {
  293.  
  294. /**
  295. * @class WZoom
  296. * @param {string|HTMLElement} selectorOrHTMLElement
  297. * @param {Object} options
  298. * @constructor
  299. */
  300.  
  301. function WZoom(selectorOrHTMLElement) {
  302. var options =
  303. arguments.length > 1 && arguments[1] !== undefined
  304. ? arguments[1]
  305. : {};
  306. this._init = this._init.bind(this);
  307. this._prepare = this._prepare.bind(this);
  308. this._computeNewScale = this._computeNewScale.bind(this);
  309. this._computeNewPosition = this._computeNewPosition.bind(this);
  310. this._transform = this._transform.bind(this);
  311. this._wheelHandler = _wheelHandler.bind(this);
  312. this._downHandler = _downHandler.bind(this);
  313. this._upHandler = _upHandler.bind(this);
  314. this._zoomTwoFingers_TouchmoveHandler = _zoomTwoFingers_TouchmoveHandler.bind(
  315. this
  316. );
  317. this._zoomTwoFingers_TouchendHandler = _zoomTwoFingers_TouchendHandler.bind(
  318. this
  319. );
  320. /********************/
  321.  
  322. /********************/
  323.  
  324. this.content = {};
  325. this.window = {};
  326. this.isTouch = false;
  327. this.events = null;
  328. this.direction = 1;
  329. this.options = null;
  330. this.dragScrollable = null; // processing of the event "max / min zoom" begin only if there was really just a click
  331. // so as not to interfere with the DragScrollable module
  332.  
  333. this.clickExpired = true;
  334. /********************/
  335.  
  336. /********************/
  337.  
  338. var defaults = {
  339. // type content: `image` - only one image, `html` - any HTML content
  340. type: 'image',
  341. // for type `image` computed auto (if width set null), for type `html` need set real html content width, else computed auto
  342. width: null,
  343. // for type `image` computed auto (if height set null), for type `html` need set real html content height, else computed auto
  344. height: null,
  345. // drag scrollable content
  346. dragScrollable: true,
  347. // options for the DragScrollable module
  348. dragScrollableOptions: {},
  349. // minimum allowed proportion of scale
  350. minScale: null,
  351. // maximum allowed proportion of scale
  352. maxScale: 1,
  353. // content resizing speed
  354. speed: 50,
  355. // zoom to maximum (minimum) size on click
  356. zoomOnClick: true,
  357. // if is true, then when the source image changes, the plugin will automatically restart init function (used with type = image)
  358. // attention: if false, it will work correctly only if the images are of the same size
  359. watchImageChange: true,
  360. };
  361.  
  362. if (typeof selectorOrHTMLElement === 'string') {
  363. this.content.$element = document.querySelector(
  364. selectorOrHTMLElement
  365. );
  366. } else if (selectorOrHTMLElement instanceof HTMLElement) {
  367. this.content.$element = selectorOrHTMLElement;
  368. } else {
  369. throw 'WZoom: `selectorOrHTMLElement` must be selector or HTMLElement, and not '.concat(
  370. {}.toString.call(selectorOrHTMLElement)
  371. );
  372. } // check if we're using a touch screen
  373.  
  374. this.isTouch = isTouch(); // switch to touch events if using a touch screen
  375.  
  376. this.events = this.isTouch
  377. ? {
  378. down: 'touchstart',
  379. up: 'touchend',
  380. }
  381. : {
  382. down: 'mousedown',
  383. up: 'mouseup',
  384. }; // if using touch screen tells the browser that the default action will not be undone
  385.  
  386. this.events.options = this.isTouch
  387. ? {
  388. passive: true,
  389. }
  390. : false;
  391.  
  392. if (this.content.$element) {
  393. this.options = extendObject(defaults, options);
  394.  
  395. if (
  396. this.options.minScale &&
  397. this.options.minScale >= this.options.maxScale
  398. ) {
  399. this.options.minScale = null;
  400. } // for window take just the parent
  401.  
  402. this.window.$element = this.content.$element.parentNode;
  403.  
  404. if (this.options.type === 'image') {
  405. var initAlreadyDone = false; // if the `image` has already been loaded
  406.  
  407. if (this.content.$element.complete) {
  408. this._init();
  409.  
  410. initAlreadyDone = true;
  411. }
  412.  
  413. if (
  414. !initAlreadyDone ||
  415. this.options.watchImageChange === true
  416. ) {
  417. // even if the `image` has already been loaded (for "hotswap" of src support)
  418. on(
  419. this.content.$element,
  420. 'load',
  421. this._init, // if watchImageChange == false listen add only until the first call
  422. this.options.watchImageChange
  423. ? false
  424. : {
  425. once: true,
  426. }
  427. );
  428. }
  429. } else {
  430. this._init();
  431. }
  432. }
  433. }
  434.  
  435. WZoom.prototype = {
  436. constructor: WZoom,
  437. _init: function _init() {
  438. this._prepare(); // support for zoom and pinch on touch screen devices
  439.  
  440. if (this.isTouch) {
  441. this.fingersHypot = null;
  442. this.zoomPinchWasDetected = false;
  443. on(
  444. this.content.$element,
  445. 'touchmove',
  446. this._zoomTwoFingers_TouchmoveHandler
  447. );
  448. on(
  449. this.content.$element,
  450. 'touchend',
  451. this._zoomTwoFingers_TouchendHandler
  452. );
  453. }
  454.  
  455. if (this.options.dragScrollable === true) {
  456. // this can happen if the src of this.content.$element (when type = image) is changed and repeat event load at image
  457. if (this.dragScrollable) {
  458. this.dragScrollable.destroy();
  459. }
  460.  
  461. this.dragScrollable = new DragScrollable(
  462. this.window,
  463. this.content,
  464. this.options.dragScrollableOptions
  465. );
  466. }
  467.  
  468. on(this.content.$element, 'wheel', this._wheelHandler);
  469.  
  470. if (this.options.zoomOnClick) {
  471. on(
  472. this.content.$element,
  473. this.events.down,
  474. this._downHandler,
  475. this.events.options
  476. );
  477. on(
  478. this.content.$element,
  479. this.events.up,
  480. this._upHandler,
  481. this.events.options
  482. );
  483. }
  484. },
  485. _prepare: function _prepare() {
  486. var windowPosition = getElementPosition(this.window.$element); // original window sizes and position
  487.  
  488. this.window.originalWidth = this.window.$element.offsetWidth;
  489. this.window.originalHeight = this.window.$element.offsetHeight;
  490. this.window.positionLeft = windowPosition.left;
  491. this.window.positionTop = windowPosition.top; // original content sizes
  492.  
  493. if (this.options.type === 'image') {
  494. this.content.originalWidth =
  495. this.options.width || this.content.$element.naturalWidth;
  496. this.content.originalHeight =
  497. this.options.height || this.content.$element.naturalHeight;
  498. } else {
  499. this.content.originalWidth =
  500. this.options.width || this.content.$element.offsetWidth;
  501. this.content.originalHeight =
  502. this.options.height || this.content.$element.offsetHeight;
  503. } // minScale && maxScale
  504.  
  505. this.content.minScale =
  506. this.options.minScale ||
  507. Math.min(
  508. this.window.originalWidth / this.content.originalWidth,
  509. this.window.originalHeight / this.content.originalHeight
  510. );
  511. this.content.maxScale = this.options.maxScale; // current content sizes and transform data
  512.  
  513. this.content.currentWidth =
  514. this.content.originalWidth * this.content.minScale;
  515. this.content.currentHeight =
  516. this.content.originalHeight * this.content.minScale;
  517. this.content.currentLeft = 0;
  518. this.content.currentTop = 0;
  519. this.content.currentScale = this.content.minScale; // calculate indent-left and indent-top to of content from window borders
  520.  
  521. this.content.correctX = Math.max(
  522. 0,
  523. (this.window.originalWidth - this.content.currentWidth) / 2
  524. );
  525. this.content.correctY = Math.max(
  526. 0,
  527. (this.window.originalHeight - this.content.currentHeight) / 2
  528. );
  529. this.content.$element.style.transform = 'translate3d(0px, 0px, 0px) scale('.concat(
  530. this.content.minScale,
  531. ')'
  532. );
  533.  
  534. if (typeof this.options.prepare === 'function') {
  535. this.options.prepare();
  536. }
  537. },
  538. _computeNewScale: function _computeNewScale(delta) {
  539. this.direction = delta < 0 ? 1 : -1;
  540. var _this$content = this.content,
  541. minScale = _this$content.minScale,
  542. maxScale = _this$content.maxScale,
  543. currentScale = _this$content.currentScale;
  544. var contentNewScale =
  545. currentScale + this.direction / this.options.speed;
  546.  
  547. if (contentNewScale < minScale) {
  548. this.direction = 1;
  549. } else if (contentNewScale > maxScale) {
  550. this.direction = -1;
  551. }
  552.  
  553. return contentNewScale < minScale
  554. ? minScale
  555. : contentNewScale > maxScale
  556. ? maxScale
  557. : contentNewScale;
  558. },
  559. _computeNewPosition: function _computeNewPosition(
  560. contentNewScale,
  561. _ref
  562. ) {
  563. var x = _ref.x,
  564. y = _ref.y;
  565. var window = this.window,
  566. content = this.content;
  567. var contentNewWidth = content.originalWidth * contentNewScale;
  568. var contentNewHeight = content.originalHeight * contentNewScale;
  569. var _document = document,
  570. body = _document.body,
  571. documentElement = _document.documentElement;
  572. var scrollLeft =
  573. window.pageXOffset ||
  574. documentElement.scrollLeft ||
  575. body.scrollLeft;
  576. var scrollTop =
  577. window.pageYOffset ||
  578. documentElement.scrollTop ||
  579. body.scrollTop; // calculate the parameters along the X axis
  580.  
  581. var leftWindowShiftX = x + scrollLeft - window.positionLeft;
  582. var centerWindowShiftX =
  583. window.originalWidth / 2 - leftWindowShiftX;
  584. var centerContentShiftX = centerWindowShiftX + content.currentLeft;
  585. var contentNewLeft =
  586. centerContentShiftX * (contentNewWidth / content.currentWidth) -
  587. centerContentShiftX +
  588. content.currentLeft; // check that the content does not go beyond the X axis
  589.  
  590. if (
  591. this.direction === -1 &&
  592. (contentNewWidth - window.originalWidth) / 2 +
  593. content.correctX <
  594. Math.abs(contentNewLeft)
  595. ) {
  596. var positive = contentNewLeft < 0 ? -1 : 1;
  597. contentNewLeft =
  598. ((contentNewWidth - window.originalWidth) / 2 +
  599. content.correctX) *
  600. positive;
  601. } // calculate the parameters along the Y axis
  602.  
  603. var topWindowShiftY = y + scrollTop - window.positionTop;
  604. var centerWindowShiftY =
  605. window.originalHeight / 2 - topWindowShiftY;
  606. var centerContentShiftY = centerWindowShiftY + content.currentTop;
  607. var contentNewTop =
  608. centerContentShiftY *
  609. (contentNewHeight / content.currentHeight) -
  610. centerContentShiftY +
  611. content.currentTop; // check that the content does not go beyond the Y axis
  612.  
  613. if (
  614. this.direction === -1 &&
  615. (contentNewHeight - window.originalHeight) / 2 +
  616. content.correctY <
  617. Math.abs(contentNewTop)
  618. ) {
  619. var _positive = contentNewTop < 0 ? -1 : 1;
  620.  
  621. contentNewTop =
  622. ((contentNewHeight - window.originalHeight) / 2 +
  623. content.correctY) *
  624. _positive;
  625. }
  626.  
  627. if (contentNewScale === this.content.minScale) {
  628. contentNewLeft = contentNewTop = 0;
  629. }
  630.  
  631. var response = {
  632. currentLeft: content.currentLeft,
  633. newLeft: contentNewLeft,
  634. currentTop: content.currentTop,
  635. newTop: contentNewTop,
  636. currentScale: content.currentScale,
  637. newScale: contentNewScale,
  638. };
  639. content.currentWidth = contentNewWidth;
  640. content.currentHeight = contentNewHeight;
  641. content.currentLeft = contentNewLeft;
  642. content.currentTop = contentNewTop;
  643. content.currentScale = contentNewScale;
  644. return response;
  645. },
  646. _transform: function _transform(_ref2) {
  647. _ref2.currentLeft;
  648. var newLeft = _ref2.newLeft;
  649. _ref2.currentTop;
  650. var newTop = _ref2.newTop;
  651. _ref2.currentScale;
  652. var newScale = _ref2.newScale;
  653. this.content.$element.style.transform = 'translate3d('
  654. .concat(newLeft, 'px, ')
  655. .concat(newTop, 'px, 0px) scale(')
  656. .concat(newScale, ')');
  657.  
  658. if (typeof this.options.rescale === 'function') {
  659. this.options.rescale();
  660. }
  661. },
  662. _zoom: function _zoom(direction) {
  663. var windowPosition = getElementPosition(this.window.$element);
  664. var window = this.window;
  665. var _document2 = document,
  666. body = _document2.body,
  667. documentElement = _document2.documentElement;
  668. var scrollLeft =
  669. window.pageXOffset ||
  670. documentElement.scrollLeft ||
  671. body.scrollLeft;
  672. var scrollTop =
  673. window.pageYOffset ||
  674. documentElement.scrollTop ||
  675. body.scrollTop;
  676.  
  677. this._transform(
  678. this._computeNewPosition(this._computeNewScale(direction), {
  679. x:
  680. windowPosition.left +
  681. this.window.originalWidth / 2 -
  682. scrollLeft,
  683. y:
  684. windowPosition.top +
  685. this.window.originalHeight / 2 -
  686. scrollTop,
  687. })
  688. );
  689. },
  690. prepare: function prepare() {
  691. this._prepare();
  692. },
  693. zoomUp: function zoomUp() {
  694. this._zoom(-1);
  695. },
  696. zoomDown: function zoomDown() {
  697. this._zoom(1);
  698. },
  699. destroy: function destroy() {
  700. this.content.$element.style.transform = '';
  701.  
  702. if (this.options.type === 'image') {
  703. off(this.content.$element, 'load', this._init);
  704. }
  705.  
  706. if (this.isTouch) {
  707. off(
  708. this.content.$element,
  709. 'touchmove',
  710. this._zoomTwoFingers_TouchmoveHandler
  711. );
  712. off(
  713. this.content.$element,
  714. 'touchend',
  715. this._zoomTwoFingers_TouchendHandler
  716. );
  717. }
  718.  
  719. off(this.window.$element, 'wheel', this._wheelHandler);
  720.  
  721. if (this.options.zoomOnClick) {
  722. off(
  723. this.window.$element,
  724. this.events.down,
  725. this._downHandler,
  726. this.events.options
  727. );
  728. off(
  729. this.window.$element,
  730. this.events.up,
  731. this._upHandler,
  732. this.events.options
  733. );
  734. }
  735.  
  736. if (this.dragScrollable) {
  737. this.dragScrollable.destroy();
  738. }
  739.  
  740. for (var key in this) {
  741. if (this.hasOwnProperty(key)) {
  742. this[key] = null;
  743. }
  744. }
  745. },
  746. };
  747.  
  748. function _wheelHandler(event) {
  749. event.preventDefault();
  750.  
  751. this._transform(
  752. this._computeNewPosition(this._computeNewScale(event.deltaY), {
  753. x: eventClientX(event),
  754. y: eventClientY(event),
  755. })
  756. );
  757. }
  758.  
  759. function _downHandler(event) {
  760. var _this = this;
  761.  
  762. if (
  763. (this.isTouch && event.touches.length === 1) ||
  764. event.buttons === 1
  765. ) {
  766. this.clickExpired = false;
  767. setTimeout(function () {
  768. return (_this.clickExpired = true);
  769. }, 150);
  770. }
  771. }
  772.  
  773. function _upHandler(event) {
  774. if (!this.clickExpired) {
  775. this._transform(
  776. this._computeNewPosition(
  777. this.direction === 1
  778. ? this.content.maxScale
  779. : this.content.minScale,
  780. {
  781. x: eventClientX(event),
  782. y: eventClientY(event),
  783. }
  784. )
  785. );
  786.  
  787. this.direction *= -1;
  788. }
  789. }
  790.  
  791. function _zoomTwoFingers_TouchmoveHandler(event) {
  792. // detect two fingers
  793. if (event.targetTouches.length === 2) {
  794. var pageX1 = event.targetTouches[0].clientX;
  795. var pageY1 = event.targetTouches[0].clientY;
  796. var pageX2 = event.targetTouches[1].clientX;
  797. var pageY2 = event.targetTouches[1].clientY; // Math.hypot() analog
  798.  
  799. var fingersHypotNew = Math.round(
  800. Math.sqrt(
  801. Math.pow(Math.abs(pageX1 - pageX2), 2) +
  802. Math.pow(Math.abs(pageY1 - pageY2), 2)
  803. )
  804. );
  805. var direction = 0;
  806. if (fingersHypotNew > this.fingersHypot + 5) direction = -1;
  807. if (fingersHypotNew < this.fingersHypot - 5) direction = 1;
  808.  
  809. if (direction !== 0) {
  810. console.log(
  811. 'move',
  812. direction,
  813. this.fingersHypot,
  814. fingersHypotNew
  815. );
  816.  
  817. if (this.fingersHypot !== null || direction === 1) {
  818. var eventEmulator = new Event('wheel'); // sized direction
  819.  
  820. eventEmulator.deltaY = direction; // middle position between fingers
  821.  
  822. eventEmulator.clientX =
  823. Math.min(pageX1, pageX2) +
  824. Math.abs(pageX1 - pageX2) / 2;
  825. eventEmulator.clientY =
  826. Math.min(pageY1, pageY2) +
  827. Math.abs(pageY1 - pageY2) / 2;
  828.  
  829. this._wheelHandler(eventEmulator);
  830. }
  831.  
  832. this.fingersHypot = fingersHypotNew;
  833. this.zoomPinchWasDetected = true;
  834. }
  835. }
  836. }
  837.  
  838. function _zoomTwoFingers_TouchendHandler() {
  839. if (this.zoomPinchWasDetected) {
  840. this.fingersHypot = null;
  841. this.zoomPinchWasDetected = false;
  842. console.log('end', this.fingersHypot);
  843. }
  844. }
  845. /**
  846. * Create WZoom instance
  847. * @param {string|HTMLElement} selectorOrHTMLElement
  848. * @param {Object} [options]
  849. * @returns {WZoom}
  850. */
  851.  
  852. WZoom.create = function (selectorOrHTMLElement, options) {
  853. return new WZoom(selectorOrHTMLElement, options);
  854. };
  855.  
  856. return WZoom;
  857. });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址