代码改变世界

原生js 基于canvas写一个简单的前端 截图

2019-04-16 15:07  muamaker  阅读(1666)  评论(0编辑  收藏  举报

 

先看效果

 

 

 

 

<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title></title>
		<style type="text/css">
			* {
				padding: 0;
				margin: 0;
				font-size: 14px;
			}

			#box {
				width: 400px;
				height: 400px;
				border: 1px solid red;
				margin: 20px auto;
				position: relative;
			}

			#operate {
				text-align: center;
				;
			}

			#operate p {
				margin-bottom: 6px;
			}

			input[type=file] {
				display: none;
			}

			label {
				display: inline-block;
				cursor: pointer;
				background: #38f;
				color: #fff;
				width: 102px;
				height: 38px;
				line-height: 38px;
				border-radius: 4px;
			}

			#clipcanvas {
				position: absolute;
				top: 0;
				left: 0;
				z-index: 10;
				width: 100%;
				height: 100%;
			}
		</style>
	</head>
	<body>
		<div id="box">
			<canvas id="canvas" width="400" height="400"></canvas>
			<canvas id="clipcanvas"></canvas>
		</div>
		<div id="operate">
			<p><label><input type="file" name="" id="bg" value="" />选择头像</label></p>
			<p><label><input type="file" name="" id="flag" value="" />选择上层</label></p>
			<p><input type="text" name="" id="posX" value="0" />请输入上层x位置</p>
			<p><input type="text" name="" id="posY" value="0" />请输入上层y位置</p>
			<p><label id="create">直接生成</label></p>
			<p><label id="reset">重新截图</label></p>
		</div>
		<a href="" download="logo.png" title="点击下载" id="down">
			<img src="" id="result">
		</a>
		
	</body>
	<script type="text/javascript">
		const canvas = document.getElementById("canvas");
		const ctx = canvas.getContext("2d");
		const baseW = 400;
		const flagW = 100;
		let bgConfig;
		let flagConfig;
		document.getElementById("bg").onchange = async function() {
			const file = this.files[0];
			try {
				const img = await getImageObj(file);
				const rate = compress(img, baseW);
				bgConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h];
				drawn();
			} catch (e) {
				console.error(e);
			}
		};

		document.getElementById("flag").onchange = async function() {
			const file = this.files[0];
			try {
				const img = await getImageObj(file);
				const rate = compress(img, flagW);
				flagConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h];
				drawn();
			} catch (e) {
				console.error(e);
			}
		};
		document.getElementById("posX").onchange = function() {
			let val = Number(this.value) || 0;
			flagConfig[5] = val;
			drawn();
		}
		document.getElementById("posY").onchange = function() {
			let val = Number(this.value) || 0;
			flagConfig[6] = val;
			drawn();
		}

		function drawn() {
			ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
			if (bgConfig) {
				ctx.drawImage(...bgConfig);
			}
			if (flagConfig) {
				ctx.drawImage(...flagConfig);
			}
		}

		//图片压缩,获取等比缩放后的结果
		function compress(img, base) {
			let w = img.width;
			let h = img.height;
			if (img.width > img.height) {
				if (img.width > base) {
					//要将宽度缩放
					w = base;
					h = (w / img.width) * img.height; // 新的 宽比 高 = 旧的宽比高  h / w = img.heigth/img.width  ;
				}
			} else {
				if (img.height > base) {
					h = base;
					w = (h / img.height) * img.width;
				}
			}
			return {
				w,
				h
			};
		}

		function getImageObj(file) {
			const url = getObjectURL(file);
			const img = new Image();
			img.src = url;
			return new Promise((resolve, reject) => {
				img.onload = function() {
					resolve(img);
				}
				img.onerror = function(e) {
					reject(e);
				}
			});
		}


		//取得该文件的url
		function getObjectURL(file) {
			var url = null;
			if (window.createObjectURL != undefined) {
				url = window.createObjectURL(file);
			} else if (window.URL != undefined) {
				url = window.URL.createObjectURL(file);
			} else if (window.webkitURL != undefined) {
				url = window.webkitURL.createObjectURL(file);
			}
			return url;
		}


		//截图
		var clipcanvas = document.getElementById("clipcanvas");
		var clipctx = clipcanvas.getContext("2d");
		
		clipcanvas.width = canvas.clientWidth;
		clipcanvas.height = canvas.clientHeight;
		var start = null;
		var clipArea = {}; //裁剪范围
		clipcanvas.onmousedown = function(e) {
			start = {
				x: e.offsetX,
				y: e.offsetY
			};
		}
		clipcanvas.onmousemove = function(e) {
			if (start) {
				fill(start.x, start.y, e.offsetX - start.x, e.offsetY - start.y)
			}
		}
		document.addEventListener("mouseup", function() {
			if (start) {
				start = null;
				exportImg(clipArea);
			}
		});
		//重新截图
		document.getElementById("reset").onclick = function(){
			clipctx.clearRect(0, 0, clipcanvas.width, clipcanvas.height);
		}
		//直接生成
		document.getElementById("create").onclick = function(){
		 	exportImg({
				x:0,
				y:0,
				w:canvas.clientWidth,
				h:canvas.clientHeight,
			})
		}
		function fill(x, y, w, h) {
			clipctx.clearRect(0, 0, clipcanvas.width, clipcanvas.height);
			clipctx.beginPath();
			clipctx.fillStyle = 'rgba(0,0,0,0.6)';
			clipctx.strokeStyle = "green";
			//遮罩层
			clipctx.globalCompositeOperation = "source-over";
			clipctx.fillRect(0, 0, clipcanvas.width, clipcanvas.height);
			//画框
			clipctx.globalCompositeOperation = 'destination-out';
			clipctx.fillRect(x, y, w, h);
			//描边
			clipctx.globalCompositeOperation = "source-over";
			clipctx.moveTo(x, y);
			clipctx.lineTo(x + w, y);
			clipctx.lineTo(x + w, y + h);
			clipctx.lineTo(x, y + h);
			clipctx.lineTo(x, y);
			clipctx.stroke();
			clipctx.closePath();
			clipArea = {
				x,
				y,
				w,
				h
			};
		}

		function startClip(area) {
			var canvas = document.createElement("canvas");
			canvas.width = area.w;
			canvas.height = area.h;
			var data = ctx.getImageData(area.x, area.y, area.w, area.h);
			var context = canvas.getContext("2d");
			context.putImageData(data, 0, 0);
			return canvas.toDataURL("image/png");
		}
		
		function exportImg(clipArea){
			var url = startClip(clipArea);
			document.getElementById("result").src = url;
			document.getElementById("down").href = url;
		}
		
	</script>
</html>