123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /**
- * zoom.js - It's the best way to zoom an image
- * @version v0.0.2
- * @link https://github.com/fat/zoom.js
- * @license MIT
- */
- +function ($) { "use strict";
- /**
- * The zoom service
- */
- function ZoomService () {
- this._activeZoom =
- this._initialScrollPosition =
- this._initialTouchPosition =
- this._touchMoveListener = null
- this._$document = $(document)
- this._$window = $(window)
- this._$body = $(document.body)
- this._boundClick = $.proxy(this._clickHandler, this)
- }
- ZoomService.prototype.listen = function () {
- this._$body.on('click', '[data-action="zoom"]', $.proxy(this._zoom, this))
- }
- ZoomService.prototype._zoom = function (e) {
- var target = e.target
- if (!target || target.tagName != 'IMG') return
- if (this._$body.hasClass('zoom-overlay-open')) return
- if (e.metaKey || e.ctrlKey) {
- return window.open((e.target.getAttribute('data-original') || e.target.src), '_blank')
- }
- if (target.width >= ($(window).width() - Zoom.OFFSET)) return
- this._activeZoomClose(true)
- this._activeZoom = new Zoom(target)
- this._activeZoom.zoomImage()
- // todo(fat): probably worth throttling this
- this._$window.on('scroll.zoom', $.proxy(this._scrollHandler, this))
- this._$document.on('keyup.zoom', $.proxy(this._keyHandler, this))
- this._$document.on('touchstart.zoom', $.proxy(this._touchStart, this))
- // we use a capturing phase here to prevent unintended js events
- // sadly no useCapture in jquery api (http://bugs.jquery.com/ticket/14953)
- if (document.addEventListener) {
- document.addEventListener('click', this._boundClick, true)
- } else {
- document.attachEvent('onclick', this._boundClick, true)
- }
- if ('bubbles' in e) {
- if (e.bubbles) e.stopPropagation()
- } else {
- // Internet Explorer before version 9
- e.cancelBubble = true
- }
- }
- ZoomService.prototype._activeZoomClose = function (forceDispose) {
- if (!this._activeZoom) return
- if (forceDispose) {
- this._activeZoom.dispose()
- } else {
- this._activeZoom.close()
- }
- this._$window.off('.zoom')
- this._$document.off('.zoom')
- document.removeEventListener('click', this._boundClick, true)
- this._activeZoom = null
- }
- ZoomService.prototype._scrollHandler = function (e) {
- if (this._initialScrollPosition === null) this._initialScrollPosition = $(window).scrollTop()
- var deltaY = this._initialScrollPosition - $(window).scrollTop()
- if (Math.abs(deltaY) >= 40) this._activeZoomClose()
- }
- ZoomService.prototype._keyHandler = function (e) {
- if (e.keyCode == 27) this._activeZoomClose()
- }
- ZoomService.prototype._clickHandler = function (e) {
- if (e.preventDefault) e.preventDefault()
- else event.returnValue = false
- if ('bubbles' in e) {
- if (e.bubbles) e.stopPropagation()
- } else {
- // Internet Explorer before version 9
- e.cancelBubble = true
- }
- this._activeZoomClose()
- }
- ZoomService.prototype._touchStart = function (e) {
- this._initialTouchPosition = e.touches[0].pageY
- $(e.target).on('touchmove.zoom', $.proxy(this._touchMove, this))
- }
- ZoomService.prototype._touchMove = function (e) {
- if (Math.abs(e.touches[0].pageY - this._initialTouchPosition) > 10) {
- this._activeZoomClose()
- $(e.target).off('touchmove.zoom')
- }
- }
- /**
- * The zoom object
- */
- function Zoom (img) {
- this._fullHeight =
- this._fullWidth =
- this._overlay =
- this._targetImageWrap = null
- this._targetImage = img
- this._$body = $(document.body)
- }
- Zoom.OFFSET = 80
- Zoom._MAX_WIDTH = 2560
- Zoom._MAX_HEIGHT = 4096
- Zoom.prototype.zoomImage = function () {
- var img = document.createElement('img')
- img.onload = $.proxy(function () {
- this._fullHeight = Number(img.height)
- this._fullWidth = Number(img.width)
- this._zoomOriginal()
- }, this)
- img.src = this._targetImage.src
- }
- Zoom.prototype._zoomOriginal = function () {
- this._targetImageWrap = document.createElement('div')
- this._targetImageWrap.className = 'zoom-img-wrap'
- this._targetImage.parentNode.insertBefore(this._targetImageWrap, this._targetImage)
- this._targetImageWrap.appendChild(this._targetImage)
- $(this._targetImage)
- .addClass('zoom-img')
- .attr('data-action', 'zoom-out')
- this._overlay = document.createElement('div')
- this._overlay.className = 'zoom-overlay'
- document.body.appendChild(this._overlay)
- this._calculateZoom()
- this._triggerAnimation()
- }
- Zoom.prototype._calculateZoom = function () {
- this._targetImage.offsetWidth // repaint before animating
- var originalFullImageWidth = this._fullWidth
- var originalFullImageHeight = this._fullHeight
- var scrollTop = $(window).scrollTop()
- var maxScaleFactor = originalFullImageWidth / this._targetImage.width
- var viewportHeight = ($(window).height() - Zoom.OFFSET)
- var viewportWidth = ($(window).width() - Zoom.OFFSET)
- var imageAspectRatio = originalFullImageWidth / originalFullImageHeight
- var viewportAspectRatio = viewportWidth / viewportHeight
- if (originalFullImageWidth < viewportWidth && originalFullImageHeight < viewportHeight) {
- this._imgScaleFactor = maxScaleFactor
- } else if (imageAspectRatio < viewportAspectRatio) {
- this._imgScaleFactor = (viewportHeight / originalFullImageHeight) * maxScaleFactor
- } else {
- this._imgScaleFactor = (viewportWidth / originalFullImageWidth) * maxScaleFactor
- }
- }
- Zoom.prototype._triggerAnimation = function () {
- this._targetImage.offsetWidth // repaint before animating
- var imageOffset = $(this._targetImage).offset()
- var scrollTop = $(window).scrollTop()
- var viewportY = scrollTop + ($(window).height() / 2)
- var viewportX = ($(window).width() / 2)
- var imageCenterY = imageOffset.top + (this._targetImage.height / 2)
- var imageCenterX = imageOffset.left + (this._targetImage.width / 2)
- this._translateY = viewportY - imageCenterY
- this._translateX = viewportX - imageCenterX
- var targetTransform = 'scale(' + this._imgScaleFactor + ')'
- var imageWrapTransform = 'translate(' + this._translateX + 'px, ' + this._translateY + 'px)'
- if ($.support.transition) {
- imageWrapTransform += ' translateZ(0)'
- }
- $(this._targetImage)
- .css({
- '-webkit-transform': targetTransform,
- '-ms-transform': targetTransform,
- 'transform': targetTransform
- })
- $(this._targetImageWrap)
- .css({
- '-webkit-transform': imageWrapTransform,
- '-ms-transform': imageWrapTransform,
- 'transform': imageWrapTransform
- })
- this._$body.addClass('zoom-overlay-open')
- }
- Zoom.prototype.close = function () {
- this._$body
- .removeClass('zoom-overlay-open')
- .addClass('zoom-overlay-transitioning')
- // we use setStyle here so that the correct vender prefix for transform is used
- $(this._targetImage)
- .css({
- '-webkit-transform': '',
- '-ms-transform': '',
- 'transform': ''
- })
- $(this._targetImageWrap)
- .css({
- '-webkit-transform': '',
- '-ms-transform': '',
- 'transform': ''
- })
- $(this._targetImage)
- .one("transitionend", $.proxy(this.dispose, this))
- }
- Zoom.prototype.dispose = function (e) {
- if (this._targetImageWrap && this._targetImageWrap.parentNode) {
- $(this._targetImage)
- .removeClass('zoom-img')
- .attr('data-action', 'zoom')
- this._targetImageWrap.parentNode.replaceChild(this._targetImage, this._targetImageWrap)
- this._overlay.parentNode.removeChild(this._overlay)
- this._$body.removeClass('zoom-overlay-transitioning')
- }
- }
- // wait for dom ready (incase script included before body)
- $(function () {
- new ZoomService().listen()
- })
- }(jQuery);
|