1. 程式人生 > >移動端圖片上傳裁切(版權歸秒為所有,僅為搬運)

移動端圖片上傳裁切(版權歸秒為所有,僅為搬運)

<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width,user-scalable=no" />
<meta name="description" content="本次公開課節選自《妙味移動端原生技法精粹揭祕》遠端課程,想要了解詳情的同學可以訪問:http://www.miaov.com/index.php/news/newsDetail/nid/155 檢視課程詳情。三週的系統課程,帶你玩轉原生H5移動端web開發">
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
body {
	margin: 0;
}	
html,
body {
	height: 100%;
}
.wrap {
	position: relative;
	height: 100%;
	overflow: hidden;
}
.page {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	background: #ccc;
}
.pageHide {
	-webkit-transform: translateY(100%);
	transform: translateY(100%);
}
.fileBtn {
	position: absolute;
	left: 50%;
	top: 50%;
	width: 200px;
	height: 50px;
	font: 20px/50px "宋體";
    text-align: center;
    border: 1px solid #179e16;
    border-radius: 5px;
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
    background: #1aad19;
    color: #fff;
}
#file {
	display: none;
}
#select {
	position: absolute;
	left: 0;
	top: 0;
	width: 200px;
	height: 200px;
	border: 2px solid #6f0;
	background: rgba(255, 255, 255, .1);
}
.left-top {
	position: absolute;
	left: -4px;
	top: -4px;
	width: 40px;
	height: 40px;
	border-left: 4px solid #6f0;
	border-top: 4px solid #6f0;
}
.right-top {
	position: absolute;
	right: -4px;
	top: -4px;
	width: 40px;
	height: 40px;
	border-right: 4px solid #6f0;
	border-top: 4px solid #6f0;
}
.left-bottom {
	position: absolute;
	left: -4px;
	bottom: -4px;
	width: 40px;
	height: 40px;
	border-left: 4px solid #6f0;
	border-bottom: 4px solid #6f0;
}
.right-bottom {
	position: absolute;
	right: -4px;
	bottom: -4px;
	width: 40px;
	height: 40px;
	border-right: 4px solid #6f0;
	border-bottom: 4px solid #6f0;
}
#mask {
	position: absolute;
	left: 0;
	width: 100%;
	bottom: 0;
	height: 30px;
	background: rgba(0, 0, 0, 0.5);
	text-align: center;
	font: 20px/30px "宋體";
}
#mask a {
	color: #fff;
}
#img {
	position: absolute;
	display: none;
}
</style>
</head>
<body>
<div class="wrap">
	<div class="page">
		<label class="fileBtn">
			點選上傳圖片
			<input type="file" id="file" accept="image/*" name="">
		</label>
	</div>
	<div class="page pageHide">
		<canvas id="c"></canvas>
		<div id="select">
			<div class="left-top"></div>
			<div class="right-top"></div>
			<div class="left-bottom"></div>
			<div class="right-bottom"></div>
		</div>
		<div id="mask">
			<a href="javascript:;" id="saveBtn">儲存</a>
		</div>
		<img src="" id="img">
	</div>	
</div>
<!--
	本次公開課節選自《妙味移動端原生技法精粹揭祕》遠端課程,想要了解詳情的同學可以訪問:http://www.miaov.com/index.php/news/newsDetail/nid/155 檢視課程詳情。三週的系統課程,帶你玩轉原生H5移動端web開發
-->
<script type="text/javascript" src="MTween.js"></script>
<script type="text/javascript">
console.log('本次公開課節選自《妙味移動端原生技法精粹揭祕》遠端課程,想要了解詳情的同學可以訪問:http://www.miaov.com/index.php/news/newsDetail/nid/155 檢視課程詳情。三週的系統課程,帶你玩轉原生H5移動端web開發');

/*
答應大家的 https://github.com/motao314/mScroll 移動端滑屏元件

	移動端圖片上傳裁切:
		1. 圖片上傳
		2. 檔案大小限制
		3. 圖片讀取
		4. 把讀取過後圖片顯示在canvas中
		5. 封裝多指操作函式
		6. 多值操作canvas中的圖縮放	
	未實現的功能:
		1. 單指拖拽封裝
		2. 單指拖拽canvas中的畫面移動
		3. 單指拖拽選框中,移動選框
		4. 單指拖拽選框的周邊,改變選框的大小
		5. canvas的圖片裁切	
*/
(function(){
	var file = document.querySelector('#file');
	var page = document.querySelectorAll('.page');
	var c = document.querySelector('#c');
	var cxt = c.getContext("2d");
	var maxSize = 10*1024*1024;
	page[1].addEventListener('touchstart', function(e) {
		e.preventDefault();
	});
	c.width = document.documentElement.clientWidth;
	c.height = document.documentElement.clientHeight;
	file.onchange = function(){
		//console.log(this.files[0]);
		if(this.files[0].size > maxSize){
			alert("對不起,您傳的檔案有點太大了");
			return;
		}
		var reader = new FileReader();
		reader.onload = function(e){
			//console.log(e.target.result);
			var img = new Image();
			img.src = e.target.result;
			img.onload = function(){
				var imgW = img.width;
				var imgH = img.height;
				var scale = 1;
				var scaleW = 1;
				var scaleH = 1;
				var x = 0;
				var y = 0;
				var startLeft = 0;//按下時手指座標
				var startTop = 0;//按下時手指座標
				var startW = 0;//按下時圖片寬度
				var satrtH = 0;//按下時圖片高度
				var isDrag = true;
				var isSelectDrag = true;
				var minW = 100;
				var minH = 100;
				/* 如果圖片較大 超出了我一屏的大小 */
				if(imgW > c.width||imgH > c.height){
					scaleW = c.width/imgW;
					scaleH = c.height/imgH;
					//計算一個縮放比例
					scale = Math.min(scaleW,scaleH);
				}
				imgW *= scale;
				imgH *= scale;
				x = (c.width - imgW)/2;
				y = (c.height - imgH)/2;
				//縮放整張圖片的尺寸,並且把圖片居中顯示了
				cxt.drawImage(img,x,y,imgW,imgH);

				/* 雙指縮放圖片 */
				gesture({
					el:page[1],
					start: function(){
						startLeft = x;
						startTop = y;
						startW = imgW;
						startH = imgH;
						isDrag = false;
						isSelectDrag = false;
					},
					change: function(e){
						//根據手指縮放比例重新計算圖片尺寸
						imgW = startW*e.scale;
						imgH = startH*e.scale;

						//根據新的圖片尺寸重新計算圖片位置
						x = startLeft + (startW -imgW)/2;
						y = startTop + (startH -imgH)/2;
						
						/* cxt.clearRect(x,y,width,height);
						清除canvas原先的畫面 */
						cxt.clearRect(0,0,c.width,c.height);
						cxt.drawImage(img,x,y,imgW,imgH);
					}
				});

				/* 單指拖拽圖片移動 */
				drag({
					el: c,
					start: function(){
						isDrag = true;
						startLeft = x;
						startTop = y;
					},
					move: function(e){
						if(isDrag){
							x = startLeft + e.disPoint.x;
							y = startTop + e.disPoint.y;
							cxt.clearRect(0,0,c.width,c.height);
							cxt.drawImage(img,x,y,imgW,imgH);
						}
					},
					end: function(e){

					}
				});

				/* 單指拖拽選框移動 */
				var select = document.querySelector('#select');
				css(select,"translateX",(page[1].clientWidth - select.offsetWidth)/2);
				css(select,"translateY",(page[1].clientHeight - select.offsetHeight)/2);
				var startSelect = {};
				var isResize = false;
				drag({
					el:select,
					start: function(){
						if(isResize){
							isSelectDrag = false;
							return;
						}
						isSelectDrag = true;
						startSelect = {
							x: css(this, "translateX"),
							y: css(this, "translateY")
						}
					},
					move: function(e){
						if(!isSelectDrag){
							return;
						}
						css(this, "translateX",startSelect.x + e.disPoint.x);
						css(this, "translateY",startSelect.y + e.disPoint.y);
					},
					end: function(){	
					}
				});
				
				/* 單指拖拽選框周邊,改變選框的大小 */

				/* 
					左上角拖拽
					1. 拿到手指移動的距離 
					2. 元素start時的寬高 - 手指移動距離 = 元素當前的寬高
					3. 元素當前的位置
					4. 最一個最小值限制
				*/
				var leftTop = document.querySelector('.left-top');
				drag({
					el:leftTop,
					start: function(){
						isResize = true;
						startSelect = {
							x: css(select,"translateX"),
							y: css(select,"translateY"),
							w: css(select,"width"),
							h: css(select,"height")
						};
					},
					move: function(e){
						var width = startSelect.w - e.disPoint.x;
						var height = startSelect.h - e.disPoint.y;
						if(width > minW){
							css(select,"width",width);
							css(select,"translateX",startSelect.x + e.disPoint.x);
						}
						if(height > minH){
							css(select,"height",height);
							css(select,"translateY",startSelect.y + e.disPoint.y);
						}
					},
					end: function(){
						isResize = false;
					}
				});
				/* 右上角 */
				var rightTop = document.querySelector('.right-top');
				drag({
					el:rightTop,
					start: function(){
						isResize = true;
						startSelect = {
							y: css(select,"translateY"),
							w: css(select,"width"),
							h: css(select,"height")
						};
					},
					move: function(e){
						var width = startSelect.w + e.disPoint.x;
						var height = startSelect.h - e.disPoint.y;
						if(width > minW){
							css(select,"width",width);
						}
						if(height > minH){
							css(select,"height",height);
							css(select,"translateY",startSelect.y + e.disPoint.y);
						}
					},
					end: function(){
						isResize = false;
					}
				});

				/* 右下角 */
				var rightBottom = document.querySelector('.right-bottom');
				drag({
					el:rightBottom,
					start: function(){
						isResize = true;
						startSelect = {
							w: css(select,"width"),
							h: css(select,"height")
						};
					},
					move: function(e){
						var width = startSelect.w + e.disPoint.x;
						var height = startSelect.h + e.disPoint.y;
						if(width > minW){
							css(select,"width",width);
						}
						if(height > minH){
							css(select,"height",height);
						}
					},
					end: function(){
						isResize = false;
					}
				});

				/* 左下角 */
				var leftBottom = document.querySelector('.left-bottom');
				drag({
					el:leftBottom,
					start: function(){
						isResize = true;
						startSelect = {
							x: css(select,"translateX"),
							w: css(select,"width"),
							h: css(select,"height")
						};
					},
					move: function(e){
						var width = startSelect.w - e.disPoint.x;
						var height = startSelect.h + e.disPoint.y;
						if(width > minW){
							css(select,"width",width);
							css(select,"translateX",startSelect.x + e.disPoint.x);
						}
						if(height > minH){
							css(select,"height",height);
						}
					},
					end: function(){
						isResize = false;
					}
				});

			};
			page[1].className = "page";
		};
		reader.readAsDataURL(this.files[0]);//把檔案讀取成dataURI
	};
	/*
		 點選儲存按鈕 裁切圖片 
			1. 獲取到選框對應的canvas中的畫面的座標以及大小
			2. 利用canvas中的 dataImage,把對應的畫面截取出來
			3. 清空canvas,把擷取的畫面重新放入canvas 
			4. 生成dataUrl
			5. 把dataUrl新增到img中

	*/
	var saveBtn = document.querySelector('#saveBtn');
	saveBtn.addEventListener('touchstart', function(e) {
		var img = document.querySelector('#img');
		var rect = select.getBoundingClientRect();
		//getImageData(x,y,w,h) 獲取canvas中的畫面
		var imgData = cxt.getImageData(rect.left,rect.top,rect.width,rect.height);
		cxt.clearRect(0,0,c.width,c.height);

		//putImageData(imgData,x,y);向canvas中新增畫面
		c.width = rect.width;
		c.height = rect.height;
		cxt.putImageData(imgData,0,0);
		var url = c.toDataURL("image/png");
		img.src = url;
		img.style.display = "block";
		c.style.display = "none";
		mask.style.display = "none";
		select.style.display = "none";
		//console.log(); 
	});
	img.addEventListener('touchstart', function(e) {
		e.stopPropagation();
	});
})();
function drag(init){
	var el = init.el;
	var isDrag = false;
	var startPoint = {};//手指按下時在頁面中座標
	el.addEventListener('touchstart', function(e) {
		if(e.touches.length < 2){
			isDrag = true;
			startPoint = {
				x: e.changedTouches[0].pageX,
				y: e.changedTouches[0].pageY
			};
			init.start&&init.start.call(el,e);
		}
	});
	el.addEventListener('touchmove', function(e) {
		if(e.touches.length < 2&&isDrag){
			var nowPoint = {
				x: e.changedTouches[0].pageX,
				y: e.changedTouches[0].pageY
			};
			e.disPoint = {
				x: nowPoint.x - startPoint.x,
				y: nowPoint.y - startPoint.y
			};
			init.move&&init.move.call(el,e);
		}
	});
	el.addEventListener('touchend', function(e) {
		if(isDrag){
			isDrag = false;
			init.end&&init.end.call(el,e);
		}
	});
}
function gesture(init){
	var isGesture = false;//判斷使用者是否在進行多指操作
	var el = init.el;
	var start = [];
	el.addEventListener('touchstart', function(e) {
		//e.touches 當前螢幕上手指列表 當手指個數>=2時認定使用者在進行多指操作
		if(e.touches.length >= 2){
			isGesture = true;
			start[0] = {
				x:e.touches[0].pageX,
				y:e.touches[0].pageY
			};
			start[1] = {
				x:e.touches[1].pageX,
				y:e.touches[1].pageY
			}
			init.start&&init.start.call(el,e);
		}
	});
	el.addEventListener('touchmove', function(e) {
		//e.touches 當前螢幕上手指列表
		if(e.touches.length >= 2&&isGesture){
			var startDis = getDis(start[0],start[1]);//手指按下時兩根手指之間的距離
			var now = [];
			now[0] = {
				x:e.touches[0].pageX,
				y:e.touches[0].pageY
			};
			now[1] = {
				x:e.touches[1].pageX,
				y:e.touches[1].pageY
			};
			var nowDis = getDis(now[0],now[1]);
			e.scale = nowDis/startDis;
			init.change&&init.change.call(el,e);
		}
	});
	el.addEventListener('touchend', function(e) {
		//e.touches 當前螢幕上手指列表
		if(isGesture){
			init.end&&init.end.call(el,e);
		}
	});
}
//alert(Math.sqrt(100*100+100*100));
//計算兩個座標點之間的距離
function getDis(point,point2){
	var x = point.x - point2.x;
	var y = point.y - point2.y;
	return Math.sqrt((x*x + y*y));
}	
</script>
</body>
</html>