1 +function ($) { "use strict"; 2 3 /** 4 * The zoom service 5 */ 6 function ZoomService () { 7 this._activeZoom = 8 this._initialScrollPosition = 9 this._initialTouchPosition = 10 this._touchMoveListener = null 11 12 this._$document = $(document) 13 this._$window = $(window) 14 this._$body = $(document.body) 15 16 this._boundClick = $.proxy(this._clickHandler, this) 17 } 18 19 ZoomService.prototype.listen = function () { 20 this._$body.on('click', '[data-action="zoom"]', $.proxy(this._zoom, this)) 21 } 22 23 ZoomService.prototype._zoom = function (e) { 24 25 var target = e.target 26 27 if (!target || target.tagName != 'IMG') return 28 29 if (this._$body.hasClass('zoom-overlay-open')) return 30 31 if (e.metaKey || e.ctrlKey) { 32 return window.open((e.target.getAttribute('data-original') || e.target.src), '_blank') 33 } 34 35 // if (target.width >= ($(window).width() - Zoom.OFFSET)) return 36 37 this._activeZoomClose(true) 38 39 this._activeZoom = new Zoom(target) 40 this._activeZoom.zoomImage() 41 42 // todo(fat): probably worth throttling this 43 this._$window.on('scroll.zoom', $.proxy(this._scrollHandler, this)) 44 45 this._$document.on('keyup.zoom', $.proxy(this._keyHandler, this)) 46 this._$document.on('touchstart.zoom', $.proxy(this._touchStart, this)) 47 48 // we use a capturing phase here to prevent unintended js events 49 // sadly no useCapture in jquery api (http://bugs.jquery.com/ticket/14953) 50 if (document.addEventListener) { 51 document.addEventListener('click', this._boundClick, true) 52 } else { 53 document.attachEvent('onclick', this._boundClick, true) 54 } 55 56 if ('bubbles' in e) { 57 if (e.bubbles) e.stopPropagation() 58 } else { 59 // Internet Explorer before version 9 60 e.cancelBubble = true 61 } 62 } 63 64 ZoomService.prototype._activeZoomClose = function (forceDispose) { 65 if (!this._activeZoom) return 66 67 if (forceDispose) { 68 this._activeZoom.dispose() 69 } else { 70 this._activeZoom.close() 71 } 72 73 this._$window.off('.zoom') 74 this._$document.off('.zoom') 75 76 document.removeEventListener('click', this._boundClick, true) 77 78 this._activeZoom = null 79 } 80 81 ZoomService.prototype._scrollHandler = function (e) { 82 if (this._initialScrollPosition === null) this._initialScrollPosition = $(window).scrollTop() 83 var deltaY = this._initialScrollPosition - $(window).scrollTop() 84 if (Math.abs(deltaY) >= 40) this._activeZoomClose() 85 } 86 87 ZoomService.prototype._keyHandler = function (e) { 88 if (e.keyCode == 27) this._activeZoomClose() 89 } 90 91 ZoomService.prototype._clickHandler = function (e) { 92 if (e.preventDefault) e.preventDefault() 93 else event.returnValue = false 94 95 if ('bubbles' in e) { 96 if (e.bubbles) e.stopPropagation() 97 } else { 98 // Internet Explorer before version 9 99 e.cancelBubble = true 100 } 101 102 this._activeZoomClose() 103 } 104 105 ZoomService.prototype._touchStart = function (e) { 106 this._initialTouchPosition = e.touches[0].pageY 107 $(e.target).on('touchmove.zoom', $.proxy(this._touchMove, this)) 108 } 109 110 ZoomService.prototype._touchMove = function (e) { 111 if (Math.abs(e.touches[0].pageY - this._initialTouchPosition) > 10) { 112 this._activeZoomClose() 113 $(e.target).off('touchmove.zoom') 114 } 115 } 116 117 118 /** 119 * The zoom object 120 */ 121 function Zoom (img) { 122 this._fullHeight = 123 this._fullWidth = 124 this._overlay = 125 this._targetImageWrap = null 126 127 this._targetImage = img 128 129 this._$body = $(document.body) 130 } 131 132 Zoom.OFFSET = 40 133 Zoom._MAX_WIDTH = 2560 134 Zoom._MAX_HEIGHT = 4096 135 136 Zoom.prototype.zoomImage = function () { 137 var img = document.createElement('img') 138 img.onload = $.proxy(function () { 139 this._fullHeight = Number(img.height) 140 this._fullWidth = Number(img.width) 141 this._zoomOriginal() 142 }, this) 143 img.src = this._targetImage.src 144 } 145 146 Zoom.prototype._zoomOriginal = function () { 147 this._targetImageWrap = document.createElement('div') 148 this._targetImageWrap.className = 'zoom-img-wrap' 149 150 this._targetImage.parentNode.insertBefore(this._targetImageWrap, this._targetImage) 151 this._targetImageWrap.appendChild(this._targetImage) 152 153 $(this._targetImage) 154 .addClass('zoom-img') 155 .attr('data-action', 'zoom-out') 156 157 this._overlay = document.createElement('div') 158 this._overlay.className = 'zoom-overlay' 159 160 document.body.appendChild(this._overlay) 161 162 this._calculateZoom() 163 this._triggerAnimation() 164 } 165 166 Zoom.prototype._calculateZoom = function () { 167 this._targetImage.offsetWidth // repaint before animating 168 169 var originalFullImageWidth = this._fullWidth 170 var originalFullImageHeight = this._fullHeight 171 172 var scrollTop = $(window).scrollTop() 173 174 var maxScaleFactor = originalFullImageWidth / this._targetImage.width 175 176 var viewportHeight = ($(window).height() - Zoom.OFFSET) 177 var viewportWidth = ($(window).width() - Zoom.OFFSET) 178 179 var imageAspectRatio = originalFullImageWidth / originalFullImageHeight 180 var viewportAspectRatio = viewportWidth / viewportHeight 181 182 if (originalFullImageWidth < viewportWidth && originalFullImageHeight < viewportHeight) { 183 this._imgScaleFactor = maxScaleFactor 184 185 } else if (imageAspectRatio < viewportAspectRatio) { 186 this._imgScaleFactor = (viewportHeight / originalFullImageHeight) * maxScaleFactor 187 188 } else { 189 this._imgScaleFactor = (viewportWidth / originalFullImageWidth) * maxScaleFactor 190 } 191 } 192 193 Zoom.prototype._triggerAnimation = function () { 194 console.log('放大的时候触发') 195 this._targetImage.offsetWidth // repaint before animating 196 197 var imageOffset = $(this._targetImage).offset() 198 var scrollTop = $(window).scrollTop() 199 200 var viewportY = scrollTop + ($(window).height() / 2) 201 var viewportX = ($(window).width() / 2) 202 203 var imageCenterY = imageOffset.top + (this._targetImage.height / 2) 204 var imageCenterX = imageOffset.left + (this._targetImage.width / 2) 205 206 this._translateY = viewportY - imageCenterY 207 this._translateX = viewportX - imageCenterX 208 209 var targetTransform = 'scale(' + this._imgScaleFactor + ')' 210 var imageWrapTransform = 'translate(' + this._translateX + 'px, ' + this._translateY + 'px)' 211 212 if ($.support.transition) { 213 imageWrapTransform += ' translateZ(0)' 214 } 215 216 $(this._targetImage) 217 .css({ 218 '-webkit-transform': targetTransform, 219 '-ms-transform': targetTransform, 220 'transform': targetTransform 221 }) 222 223 $(this._targetImageWrap) 224 .css({ 225 '-webkit-transform': imageWrapTransform, 226 '-ms-transform': imageWrapTransform, 227 'transform': imageWrapTransform 228 }) 229 230 this._$body.addClass('zoom-overlay-open') 231 } 232 233 Zoom.prototype.close = function () { 234 console.log('缩回的时候出发1'); 235 this._$body 236 .removeClass('zoom-overlay-open') 237 .addClass('zoom-overlay-transitioning') 238 239 // we use setStyle here so that the correct vender prefix for transform is used 240 $(this._targetImage) 241 .css({ 242 '-webkit-transform': '', 243 '-ms-transform': '', 244 'transform': '' 245 }) 246 247 $(this._targetImageWrap) 248 .css({ 249 '-webkit-transform': '', 250 '-ms-transform': '', 251 'transform': '' 252 }) 253 254 if (!$.support.transition) { 255 return this.dispose() 256 } 257 258 $(this._targetImage) 259 .one($.support.transition.end, $.proxy(this.dispose, this)) 260 .emulateTransitionEnd(300) 261 } 262 263 Zoom.prototype.dispose = function () { 264 console.log('缩回的时候出发2') 265 if (this._targetImageWrap && this._targetImageWrap.parentNode) { 266 $(this._targetImage) 267 .removeClass('zoom-img') 268 .attr('data-action', 'zoom') 269 270 this._targetImageWrap.parentNode.replaceChild(this._targetImage, this._targetImageWrap) 271 this._overlay.parentNode.removeChild(this._overlay) 272 273 this._$body.removeClass('zoom-overlay-transitioning') 274 } 275 } 276 277 // wait for dom ready (incase script included before body) 278 $(function () { 279 new ZoomService().listen() 280 }) 281 282 }(jQuery)