| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 | (function($, window) {	var CLASS_ZOOM = $.className('zoom');	var CLASS_ZOOM_SCROLLER = $.className('zoom-scroller');	var SELECTOR_ZOOM = '.' + CLASS_ZOOM;	var SELECTOR_ZOOM_SCROLLER = '.' + CLASS_ZOOM_SCROLLER;	var EVENT_PINCH_START = 'pinchstart';	var EVENT_PINCH = 'pinch';	var EVENT_PINCH_END = 'pinchend';	if ('ongesturestart' in window) {		EVENT_PINCH_START = 'gesturestart';		EVENT_PINCH = 'gesturechange';		EVENT_PINCH_END = 'gestureend';	}	$.Zoom = function(element, options) {		var zoom = this;		zoom.options = $.extend($.Zoom.defaults, options);		zoom.wrapper = zoom.element = element;		zoom.scroller = element.querySelector(SELECTOR_ZOOM_SCROLLER);		zoom.scrollerStyle = zoom.scroller && zoom.scroller.style;		zoom.zoomer = element.querySelector(SELECTOR_ZOOM);		zoom.zoomerStyle = zoom.zoomer && zoom.zoomer.style;		zoom.init = function() {			//自动启用			$.options.gestureConfig.pinch = true;			$.options.gestureConfig.doubletap = true;			zoom.initEvents();		};		zoom.initEvents = function(detach) {			var action = detach ? 'removeEventListener' : 'addEventListener';			var target = zoom.scroller;			target[action](EVENT_PINCH_START, zoom.onPinchstart);			target[action](EVENT_PINCH, zoom.onPinch);			target[action](EVENT_PINCH_END, zoom.onPinchend);			target[action]($.EVENT_START, zoom.onTouchstart);			target[action]($.EVENT_MOVE, zoom.onTouchMove);			target[action]($.EVENT_CANCEL, zoom.onTouchEnd);			target[action]($.EVENT_END, zoom.onTouchEnd);			target[action]('drag', zoom.dragEvent);			target[action]('doubletap', zoom.doubleTapEvent);		};		zoom.dragEvent = function(e) {			if (imageIsMoved || isGesturing) {				e.stopPropagation();			}		};		zoom.doubleTapEvent = function(e) {			zoom.toggleZoom(e.detail.center);		};		zoom.transition = function(style, time) {			time = time || 0;			style['webkitTransitionDuration'] = time + 'ms';			return zoom;		};		zoom.translate = function(style, x, y) {			x = x || 0;			y = y || 0;			style['webkitTransform'] = 'translate3d(' + x + 'px,' + y + 'px,0px)';			return zoom;		};		zoom.scale = function(style, scale) {			scale = scale || 1;			style['webkitTransform'] = 'translate3d(0,0,0) scale(' + scale + ')';			return zoom;		};		zoom.scrollerTransition = function(time) {			return zoom.transition(zoom.scrollerStyle, time);		};		zoom.scrollerTransform = function(x, y) {			return zoom.translate(zoom.scrollerStyle, x, y);		};		zoom.zoomerTransition = function(time) {			return zoom.transition(zoom.zoomerStyle, time);		};		zoom.zoomerTransform = function(scale) {			return zoom.scale(zoom.zoomerStyle, scale);		};		// Gestures		var scale = 1,			currentScale = 1,			isScaling = false,			isGesturing = false;		zoom.onPinchstart = function(e) {			isGesturing = true;		};		zoom.onPinch = function(e) {			if (!isScaling) {				zoom.zoomerTransition(0);				isScaling = true;			}			scale = (e.detail ? e.detail.scale : e.scale) * currentScale;			if (scale > zoom.options.maxZoom) {				scale = zoom.options.maxZoom - 1 + Math.pow((scale - zoom.options.maxZoom + 1), 0.5);			}			if (scale < zoom.options.minZoom) {				scale = zoom.options.minZoom + 1 - Math.pow((zoom.options.minZoom - scale + 1), 0.5);			}			zoom.zoomerTransform(scale);		};		zoom.onPinchend = function(e) {			scale = Math.max(Math.min(scale, zoom.options.maxZoom), zoom.options.minZoom);			zoom.zoomerTransition(zoom.options.speed).zoomerTransform(scale);			currentScale = scale;			isScaling = false;		};		zoom.setZoom = function(newScale) {			scale = currentScale = newScale;			zoom.scrollerTransition(zoom.options.speed).scrollerTransform(0, 0);			zoom.zoomerTransition(zoom.options.speed).zoomerTransform(scale);		};		zoom.toggleZoom = function(position, speed) {			if (typeof position === 'number') {				speed = position;				position = undefined;			}			speed = typeof speed === 'undefined' ? zoom.options.speed : speed;			if (scale && scale !== 1) {				scale = currentScale = 1;				zoom.scrollerTransition(speed).scrollerTransform(0, 0);			} else {				scale = currentScale = zoom.options.maxZoom;				if (position) {					var offset = $.offset(zoom.zoomer);					var top = offset.top;					var left = offset.left;					var offsetX = (position.x - left) * scale;					var offsetY = (position.y - top) * scale;					this._cal();					if (offsetX >= imageMaxX && offsetX <= (imageMaxX + wrapperWidth)) { //center						offsetX = imageMaxX - offsetX + wrapperWidth / 2;					} else if (offsetX < imageMaxX) { //left						offsetX = imageMaxX - offsetX + wrapperWidth / 2;					} else if (offsetX > (imageMaxX + wrapperWidth)) { //right						offsetX = imageMaxX + wrapperWidth - offsetX - wrapperWidth / 2;					}					if (offsetY >= imageMaxY && offsetY <= (imageMaxY + wrapperHeight)) { //middle						offsetY = imageMaxY - offsetY + wrapperHeight / 2;					} else if (offsetY < imageMaxY) { //top						offsetY = imageMaxY - offsetY + wrapperHeight / 2;					} else if (offsetY > (imageMaxY + wrapperHeight)) { //bottom						offsetY = imageMaxY + wrapperHeight - offsetY - wrapperHeight / 2;					}					offsetX = Math.min(Math.max(offsetX, imageMinX), imageMaxX);					offsetY = Math.min(Math.max(offsetY, imageMinY), imageMaxY);					zoom.scrollerTransition(speed).scrollerTransform(offsetX, offsetY);				} else {					zoom.scrollerTransition(speed).scrollerTransform(0, 0);				}			}			zoom.zoomerTransition(speed).zoomerTransform(scale);		};		zoom._cal = function() {			wrapperWidth = zoom.wrapper.offsetWidth;			wrapperHeight = zoom.wrapper.offsetHeight;			imageWidth = zoom.zoomer.offsetWidth;			imageHeight = zoom.zoomer.offsetHeight;			var scaledWidth = imageWidth * scale;			var scaledHeight = imageHeight * scale;			imageMinX = Math.min((wrapperWidth / 2 - scaledWidth / 2), 0);			imageMaxX = -imageMinX;			imageMinY = Math.min((wrapperHeight / 2 - scaledHeight / 2), 0);			imageMaxY = -imageMinY;		};		var wrapperWidth, wrapperHeight, imageIsTouched, imageIsMoved, imageCurrentX, imageCurrentY, imageMinX, imageMinY, imageMaxX, imageMaxY, imageWidth, imageHeight, imageTouchesStart = {},			imageTouchesCurrent = {},			imageStartX, imageStartY, velocityPrevPositionX, velocityPrevTime, velocityX, velocityPrevPositionY, velocityY;		zoom.onTouchstart = function(e) {			e.preventDefault();			imageIsTouched = true;			imageTouchesStart.x = e.type === $.EVENT_START ? e.targetTouches[0].pageX : e.pageX;			imageTouchesStart.y = e.type === $.EVENT_START ? e.targetTouches[0].pageY : e.pageY;		};		zoom.onTouchMove = function(e) {			e.preventDefault();			if (!imageIsTouched) return;			if (!imageIsMoved) {				wrapperWidth = zoom.wrapper.offsetWidth;				wrapperHeight = zoom.wrapper.offsetHeight;				imageWidth = zoom.zoomer.offsetWidth;				imageHeight = zoom.zoomer.offsetHeight;				var translate = $.parseTranslateMatrix($.getStyles(zoom.scroller, 'webkitTransform'));				imageStartX = translate.x || 0;				imageStartY = translate.y || 0;				zoom.scrollerTransition(0);			}			var scaledWidth = imageWidth * scale;			var scaledHeight = imageHeight * scale;			if (scaledWidth < wrapperWidth && scaledHeight < wrapperHeight) return;			imageMinX = Math.min((wrapperWidth / 2 - scaledWidth / 2), 0);			imageMaxX = -imageMinX;			imageMinY = Math.min((wrapperHeight / 2 - scaledHeight / 2), 0);			imageMaxY = -imageMinY;			imageTouchesCurrent.x = e.type === $.EVENT_MOVE ? e.targetTouches[0].pageX : e.pageX;			imageTouchesCurrent.y = e.type === $.EVENT_MOVE ? e.targetTouches[0].pageY : e.pageY;			if (!imageIsMoved && !isScaling) {				//				if (Math.abs(imageTouchesCurrent.y - imageTouchesStart.y) < Math.abs(imageTouchesCurrent.x - imageTouchesStart.x)) {				//TODO 此处需要优化,当遇到长图,需要上下滚动时,下列判断会导致滚动不流畅				if (					(Math.floor(imageMinX) === Math.floor(imageStartX) && imageTouchesCurrent.x < imageTouchesStart.x) ||					(Math.floor(imageMaxX) === Math.floor(imageStartX) && imageTouchesCurrent.x > imageTouchesStart.x)				) {					imageIsTouched = false;					return;				}				//				}			}			imageIsMoved = true;			imageCurrentX = imageTouchesCurrent.x - imageTouchesStart.x + imageStartX;			imageCurrentY = imageTouchesCurrent.y - imageTouchesStart.y + imageStartY;			if (imageCurrentX < imageMinX) {				imageCurrentX = imageMinX + 1 - Math.pow((imageMinX - imageCurrentX + 1), 0.8);			}			if (imageCurrentX > imageMaxX) {				imageCurrentX = imageMaxX - 1 + Math.pow((imageCurrentX - imageMaxX + 1), 0.8);			}			if (imageCurrentY < imageMinY) {				imageCurrentY = imageMinY + 1 - Math.pow((imageMinY - imageCurrentY + 1), 0.8);			}			if (imageCurrentY > imageMaxY) {				imageCurrentY = imageMaxY - 1 + Math.pow((imageCurrentY - imageMaxY + 1), 0.8);			}			//Velocity			if (!velocityPrevPositionX) velocityPrevPositionX = imageTouchesCurrent.x;			if (!velocityPrevPositionY) velocityPrevPositionY = imageTouchesCurrent.y;			if (!velocityPrevTime) velocityPrevTime = $.now();			velocityX = (imageTouchesCurrent.x - velocityPrevPositionX) / ($.now() - velocityPrevTime) / 2;			velocityY = (imageTouchesCurrent.y - velocityPrevPositionY) / ($.now() - velocityPrevTime) / 2;			if (Math.abs(imageTouchesCurrent.x - velocityPrevPositionX) < 2) velocityX = 0;			if (Math.abs(imageTouchesCurrent.y - velocityPrevPositionY) < 2) velocityY = 0;			velocityPrevPositionX = imageTouchesCurrent.x;			velocityPrevPositionY = imageTouchesCurrent.y;			velocityPrevTime = $.now();			zoom.scrollerTransform(imageCurrentX, imageCurrentY);		};		zoom.onTouchEnd = function(e) {			if (!e.touches.length) {				isGesturing = false;			}			if (!imageIsTouched || !imageIsMoved) {				imageIsTouched = false;				imageIsMoved = false;				return;			}			imageIsTouched = false;			imageIsMoved = false;			var momentumDurationX = 300;			var momentumDurationY = 300;			var momentumDistanceX = velocityX * momentumDurationX;			var newPositionX = imageCurrentX + momentumDistanceX;			var momentumDistanceY = velocityY * momentumDurationY;			var newPositionY = imageCurrentY + momentumDistanceY;			if (velocityX !== 0) momentumDurationX = Math.abs((newPositionX - imageCurrentX) / velocityX);			if (velocityY !== 0) momentumDurationY = Math.abs((newPositionY - imageCurrentY) / velocityY);			var momentumDuration = Math.max(momentumDurationX, momentumDurationY);			imageCurrentX = newPositionX;			imageCurrentY = newPositionY;			var scaledWidth = imageWidth * scale;			var scaledHeight = imageHeight * scale;			imageMinX = Math.min((wrapperWidth / 2 - scaledWidth / 2), 0);			imageMaxX = -imageMinX;			imageMinY = Math.min((wrapperHeight / 2 - scaledHeight / 2), 0);			imageMaxY = -imageMinY;			imageCurrentX = Math.max(Math.min(imageCurrentX, imageMaxX), imageMinX);			imageCurrentY = Math.max(Math.min(imageCurrentY, imageMaxY), imageMinY);			zoom.scrollerTransition(momentumDuration).scrollerTransform(imageCurrentX, imageCurrentY);		};		zoom.destroy = function() {			zoom.initEvents(true); //detach			delete $.data[zoom.wrapper.getAttribute('data-zoomer')];			zoom.wrapper.setAttribute('data-zoomer', '');		}		zoom.init();		return zoom;	};	$.Zoom.defaults = {		speed: 300,		maxZoom: 3,		minZoom: 1,	};	$.fn.zoom = function(options) {		var zoomApis = [];		this.each(function() {			var zoomApi = null;			var self = this;			var id = self.getAttribute('data-zoomer');			if (!id) {				id = ++$.uuid;				$.data[id] = zoomApi = new $.Zoom(self, options);				self.setAttribute('data-zoomer', id);			} else {				zoomApi = $.data[id];			}			zoomApis.push(zoomApi);		});		return zoomApis.length === 1 ? zoomApis[0] : zoomApis;	};})(mui, window);
 |