利用原生JS完成图片裁剪

前言

最近在给一个项目添加图片编辑功能。要进行图片编辑,最重要要能够对图片进行裁剪。这是一个很有意思的功能,我花了一天的时间写了一个简单的图片裁剪的功能。现在就跟大家分享一下。

主要的实现分成两部分,一部分是前端利用js进行裁剪区域选择,第二部分是利用PHP进行后台处理。

功能

由于本人的js水平有限,所以今天所说的图片裁剪不具有很强大的功能。如果,您想要更加强大的功能可以使用JCrop插件,这个插件是一个强大的图片裁剪插件,UI也很漂亮。下载地址本文最后会贴出。

下面是我自己写的图片裁剪的功能介绍:

可以利用鼠标拖拉,产生裁剪框 可以改变裁剪框大小 点击确定,返回裁剪数据

原理

完成裁剪的方法有两种:

1、利用HTML5新增拖拽事件drag drop等 2、传统方法,利用鼠标事件,mousedown、mousemove等

在这里,我们采用方法2。

裁剪区域的形成

要进行裁剪首先要形成裁剪区域,这个裁剪区域的形成我们可以与鼠标移动的距离相关联。鼠标移动多远,裁剪区域就有多大。如下图:

如上图所示鼠标的横向移动距离与纵向移动距离共同组成了裁剪区域的宽和高。

而这横向与纵向移动的距离如何计算呢?当我们点下鼠标时,就能够通过event事件对象获取鼠标点击位置,而移动鼠标时,也能够通过event获取鼠标的位置,通过两次鼠标位置的改变,就能够获得鼠标的移动距离。

获取鼠标位置的属性是clientX以及clientY

阴影区域的形成

接下来就是绘制阴影区域。被裁剪图片中除裁剪区域以外的部分,都属于阴影部分,也可以不绘制该区域,绘制该区域是为了让用户更清晰的看清裁剪区域。

我将该区域分成了上下左右四个部分,见下图分布:

那么该区域如果计算呢?这时就要用到Dom元素的偏移值了,利用裁剪区域的左偏移值减去图片本身的左偏移值就是左阴影的宽,利用裁剪区域的上偏移值减去图片的上偏移值,等于上阴影的高度值。如下图:

获取到左阴影、上阴影的值后,就能够通过这两个将其他阴影的属性计算出来。

图片的偏移值有两种取法

  • 利用offsetLeft 与 offsetTop 值 弊端 如果dom元素有border margin等值会将这些值计算在内
  • 获取dom的css属性 弊端 预定义的css有关 如果没定义left top就无法获取

这两种方法都有各自的弊端,视不同情况来使用

裁剪越界的阻止

裁剪区域的计算是通过鼠标的移动距离来计算的,因此会出现裁剪区域越界的情况,而这情况又分成两种:

裁剪过程中越界 移动裁剪区域时越界

那么下面就来说说如何防止越界。

裁剪越界

什么是裁剪时越界?就是鼠标拖动区域超出了图片的返回,形成了越界,如下图:

对于这种越界需要判断裁剪区域的右侧相对于浏览器左侧的位置 不能够超过 图片右侧的位置相当于浏览器左侧的位置;同时裁剪区域底部相对于浏览器顶部位置 不能够超过 图片底部相对应浏览器顶部的位置。还是画图来说明:

TX >= PX 时就让TX的值强制为一固定值。

TX与PX的计算方法,假设裁剪区域为oTailor,图片区域oPicture:

TX = oTailor.offsetWidth + oTailor.offsetLeft;
PX = oPicture.offsetWidth + oPicture.offsetLeft;
复制代码

同理,可以按照上述方法对左侧越界,上侧越界,下侧越界进行限制,就不多赘述。

移动越界

移动越界指的是已经形成了裁剪区域了,但通过鼠标移动裁剪区域时产生了越界。这个理解比较简单,就不画图介绍了。这种越界与dom拖拽越界限制一致,通过判断鼠标移动距离是否超过了图片区域来判断。

原理与问题解决了,现在开始来完成实际功能。

准备工作

在做之前,先做一些准备工作,磨刀不误砍柴功。

网页布局准备

网页布局部分关键代码如下:

<img src="./images/img_2.jpg" alt="">
<div class="img_box">
	<div class="box_border1"></div>
	<div class="box_border2"></div>
	<div class="box_border3"></div>
	<div class="box_border4"></div>
	<div class="box_handle" id="box_1"></div>
	<div class="box_handle" id="box_2"></div>
	<div class="box_handle" id="box_3"></div>
	<div class="box_handle" id="box_4"></div>
	<div class="box_handle" id="box_5"></div>
	<div class="box_handle" id="box_6"></div>
	<div class="box_handle" id="box_7"></div>
	<div class="box_handle" id="box_8"></div>
</div>
<!-- 左 -->
<div class="outer"></div>
<!-- 上 -->		
<div class="outer"></div>
<!-- 右 -->		
<div class="outer"></div>
<!-- 下 -->		
<div class="outer"></div>

<button class="confirm">确定</button>
复制代码

其中img_box表示的是裁剪区域,outer表示阴影区域,而img_box中的div是裁剪区域的边框

样式控制如下:

* {
	padding:0;
	margin:0;
}
body {
	
	background: #454545;		
}                   
.main {
	width: 500px;
	margin:50px auto;
}
.main img {
	width: 500px;
	position: absolute;
	left: 450px;
	top: 50px;
}
.img_box {		
	overflow: hidden;
	position: absolute;
	top:0px;
	left: 0px;
	z-index: 2;
}
.outer {
	overflow: hidden;
	background: #000;
	opacity: 0.4;
	position: absolute;
	top:0px;
	left: 0px;
	z-index: 0;
}
.box_border1 ,
.box_border2 ,
.box_border3 ,
.box_border4 {
	opacity: 0.5;
}
.box_border1 {
	background: url(./images/border-anim-v.gif) repeat-y left top;
} 
.box_border2 {
	background: url(./images/border-anim-h.gif) repeat-x left top;
}
.box_border3 {
	background: url(./images/border-anim-v.gif) repeat-y right top;
} 
.box_border4 {
	background: url(./images/border-anim-h.gif) repeat-x right bottom;
} 
.box_handle {		
	background: #fff;
	border: 1px solid #000;
	opacity: 0.5;
}
.confrim {
	width: 80px;
	height: 35px;
}
复制代码

布局效果如下:

通用函数

完成图片裁剪,通过上述原理,可以知道需要大量获取标签对象以及标签的css属性等,所以可以编写通用函数,更好的获取这些值。如下:

Dom获取函数

这个函数以前写的文章中有提过利用HTML5与ajax完成拖拽上传文件,不过那篇文章中提供的函数有bug,现在重写一下:

/* 	 仿JqueryDom获取	 */
function $(dom) {

 	function getDom(dom) {

		var str = dom.charAt(0);		
		switch( str ) {
			case '.' :
				this.ele = document.getElementsByClassName(dom.substring(1))||null;	
							
				break;
			
			case '#' :

				this.ele =  document.getElementById(dom.substring(1)) || null;

				break;

			default : 

				if(document.getElementsByTagName(dom).length) {

					this.ele = document.getElementsByTagName(dom);								

				} else if(document.getElementsByName(dom).length) {

					this.ele = document.getElementsByName(dom);									

				} else {					
					this.ele = null;
				}
		}
		return this;			
	};


	getDom.prototype.get = function(num) {
		return this.ele[num]||this.ele;
	}

	getDom.prototype.insert = function(value , num) {
		this.ele[num].innerHTML = value;			
	}

	return new getDom(dom);
}
复制代码
Css属性获取函数

Css属性的获取分成两种,一种是IE的,使用currentStyle;另一种是其他主流浏览器,使用getComputedStyle,以下是兼容版本:

/*  Css获取  */
function getCss(o , key){
	return o.currentStyle? o.currentStyle[key] : document.defaultView.getComputedStyle(o,false)[key]; 	
};
复制代码
赋值函数

编写时经常遇到对Dom的样式进行赋值,为方便,我专门编写了一个函数用于赋值:

/**
- 赋值函数  
- @param : obj	 	被赋值对象
- @param : option   进行的操作
- @parma : value	赋值内容
 */
function setAssign(obj , option , value) {	
	
	switch(option) {
		case 'width':
			obj.style.width = value;
			break;
		case 'height':
			obj.style.height = value;
			break;
		case 'top':
			obj.style.top = value;
			break;
		case 'left':
			obj.style.left = value;
			break;
		case 'position':
			obj.style.position = value;
			break;
		case 'cursor':
			obj.style.cursor = value;
	}
}
复制代码

好了准备工作基本完成,现在就正式开始编写。

通过点击与移动事件完成裁剪区域绘制

对图片设置mousedown以及mousemove事件监视,如下:

// 鼠标点击图片触发
oPicture.onmousedown = function(ev) {
	// 事件对象
	var oEvent = ev || window.event;
	
	// 初始鼠标位置
	var tempX = oEvent.clientX;
	var tempY = oEvent.clientY;			
	
	// 调整裁剪区域位置
	oTailor.style.left = oEvent.clientX + 'px';
	oTailor.style.top = oEvent.clientY + 'px';

	// 鼠标在图片上移动 绘制裁剪区域 阴影区域
	document.onmousemove = function(ev) {
		
		// 鼠标移动事件对象
		var oEvent = ev || window.event;
	
		// 当前鼠标位置减去鼠标之前的鼠标位置 等于 鼠标移动距离
		var sLeft = oEvent.clientX - tempX;
		var sTop = oEvent.clientY - tempY;
		
		// 裁剪越界限制 只需限制右侧 与 下侧
		if((oTailor.offsetLeft+oTailor.offsetWidth) >= (oPicture.offsetLeft+oPicture.offsetWidth)) {
			sLeft = oPicture.offsetLeft+oPicture.offsetWidth - oTailor.offsetLeft;
		}	
		if((oTailor.offsetTop+oTailor.offsetHeight) >= (oPicture.offsetTop+oPicture.offsetHeight)) {
			sTop = oPicture.offsetTop+oPicture.offsetHeight - oTailor.offsetTop;
		}
		
		// 裁剪区域绘制
		oTailor.style.width = sLeft + 'px';
		oTailor.style.height = sTop + 'px';

		// 裁剪区域显示
		oTailor.style.display = 'block';
		
		// 阴影区域显示
		for (var i = 0; i < oShadow.length; i++) {
			oShadow[i].style.display = 'block';
		}

		// 阴影区域绘制
		shadow(oPicture , oTailor , oShadow);

		// 添加裁剪边框
		tailorBorder(oDiv  , oHandle , oTailor);

		// 阻止默认事件
		oEvent.preventDefault();
	};

	// 鼠标松开 将移动事件取消
	document.onmouseup = function(ev) {
		var oEvent = ev || window.event;
			
		// 移动事件取消
		document.onmousemove = null;
		
		// 阻止默认事件
		oEvent.preventDefault();
	};
	
	// 阻止默认事件
	oEvent.preventDefault();
}
复制代码

阴影区域绘制

/** 
 * @param:oPicture   	图片dom对象
 * @param:oTailor   	裁剪区域dom对象
 * @param:oShadow   	阴影区域dom对象
 */ 
function shadow(oPicture , oTailor , oShadow) {	

	// 左侧阴影区
	setAssign(oShadow[0] , 'width'  , (parseInt(getCss(oTailor , 'left')) - parseInt(getCss(oPicture , 'left'))) + 'px');
	setAssign(oShadow[0] , 'height' , parseInt(getCss(oPicture , 'height')) + 'px');
	setAssign(oShadow[0] , 'left'   , parseInt(getCss(oPicture , 'left')) + 'px')
	setAssign(oShadow[0] , 'top'    , parseInt(getCss(oPicture , 'top')) + 'px')

	//右侧阴影区
	setAssign(oShadow[2] , 'width'  , (parseInt(getCss(oPicture , 'width')) - parseInt(getCss(oTailor ,'width')) - parseInt(getCss(oShadow[0] , 'width'))) + 'px');
	setAssign(oShadow[2] , 'height' , parseInt(getCss(oPicture , 'height')) + 'px');
	setAssign(oShadow[2] , 'left'	, (parseInt(getCss(oTailor , 'left')) + parseInt(getCss(oTailor , 'width'))) + 'px');
	setAssign(oShadow[2] , 'top'	, parseInt(getCss(oPicture , 'top')) + 'px');

	// 上侧阴影区
	setAssign(oShadow[1] , 'width'  , parseInt(getCss(oTailor , 'width')) + 'px');
	setAssign(oShadow[1] , 'height' , (parseInt(getCss(oTailor , 'top')) - parseInt(getCss(oPicture , 'top'))) + 'px');
	setAssign(oShadow[1] , 'left'	, (parseInt(getCss(oPicture , 'left')) + parseInt(getCss(oShadow[0] , 'width'))) + 'px');
	setAssign(oShadow[1] , 'top'	, parseInt(getCss(oPicture , 'top')) + 'px');

	// 下侧阴影区
	setAssign(oShadow[3] , 'width'  , parseInt(getCss(oTailor , 'width')) + 'px');
	setAssign(oShadow[3] , 'height' , (parseInt(getCss(oPicture , 'height')) - parseInt(getCss(oTailor , 'height')) - parseInt(getCss(oShadow[1] , 'height'))) + 'px');
	setAssign(oShadow[3] , 'left'	, (parseInt(getCss(oPicture , 'left' )) + parseInt(getCss(oShadow[0] , 'width'))) + 'px');
	setAssign(oShadow[3] , 'top'	, (parseInt(getCss(oTailor , 'top' )) + parseInt(getCss(oTailor , 'height'))) + 'px');
复制代码

}

注意在网页实际运用中,如果布局中图片css中没有left或top属性,那么上面代码会产生错误。应该使用offsetLeft与offsetTop代替之。

添加裁剪边框

在放出的布局图中,可以看见裁剪的边沿,四角及四边各有一个小正方形的形状,添加不仅是为了区分裁剪区与非裁剪区,还为下一步添加拉伸裁剪区域提供方便。下面开始编写代码:

/**
 * 	裁剪边框绘制
 * 	@param : oDIv   	所有边框对象
 * 	@param : oHandle 	点状边沿
 *  @param : oTailor    裁剪对象
 */
function tailorBorder(oDiv  , oHandle , oTailor) {
	// 对边框进行初始化
	for (var i = 0; i < oDiv.length; i++) {
		setAssign(oDiv[i] , 'position' , 'absolute');
		setAssign(oDiv[i] , 'top'	   , '0px');
		setAssign(oDiv[i] , 'left' 	   , '0px');
		setAssign(oDiv[i] , 'width'    , parseInt(getCss(oTailor , 'width')) + 'px');
		setAssign(oDiv[i] , 'height'   , parseInt(getCss(oTailor , 'height')) + 'px');
	}
	
	/* 点状边沿绘制  */	
	// 四角点状边沿绘制
	for (var i = 0; i < 4; i++) {	
		
		// 点状绘制
		setAssign(oHandle[i] , 'position'  , 'absolute');
		setAssign(oHandle[i] , 'width'	   , '5px');
		setAssign(oHandle[i] , 'height'    , '5px');
		
		// 0 2 表示左侧点状
		if(i % 2 == 0) {
			setAssign(oHandle[i] , 'left'  , '0px');
			
			setAssign(oHandle[i] , 'top'   , (i == 0?'0px' : (parseInt(getCss(oTailor , 'height')) - 8) + 'px'));			
		
		} else {
			// 右侧点状
			setAssign(oHandle[i] , 'left'  , ( parseInt(getCss(oTailor , 'width')) - 6 ) + 'px');
			
			setAssign(oHandle[i] , 'top'   , (i == 1?'0px' : parseInt(getCss(oTailor , 'height')) - 8 ) + 'px');					
		}															
	}

	// 四边点状边框
	for (var i = 4; i < oHandle.length; i++) {
		setAssign(oHandle[i] , 'position'  , 'absolute');
		setAssign(oHandle[i] , 'width'	   , '5px');
		setAssign(oHandle[i] , 'height'    , '5px');

		// 4 6 表示上 下 点状边框
		if(i % 2 == 0) {

			setAssign(oHandle[i] , 'left'  , parseInt(getCss(oTailor , 'width')) / 2 + 'px');

			setAssign(oHandle[i] , 'top'   , (i == 4 ? '0px' : (parseInt(getCss(oTailor , 'height')) - 8) + 'px'));
			
		} else {

			// 左右点状
			setAssign(oHandle[i] , 'top'   , parseInt(getCss(oTailor , 'height')) / 2 + 'px');
			
			setAssign(oHandle[i] , 'left'  ,(i == 5 ? '0px' : parseInt(getCss(oTailor , 'width')) - 8 ) + 'px');
			
		}
	}
}	
复制代码

布局中,裁剪区域类名为box_handle的div前四个代表四角的点状,后四个表示边沿中间的点状,都按照顺时针分布。完成后效果如下:

监视阴影区域

裁剪区域与阴影区域绘制完成,现在添加一个小功能,当鼠标点击到非裁剪区时(即阴影区),取消裁剪区域。

// 对阴影区域设置时间 点击到阴影区时 裁剪区域消失 阴影区消失
for (var i = 0; i < oShadow.length; i++) {
	oShadow[i].index = i;
	oShadow[i].onmousedown = function() {
		
		oTailor.style.display = 'none';
		oTailor.style.width = '0px';
		oTailor.style.hegiht = '0px';
		for (var i = 0; i < oShadow.length; i++) {
			oShadow[i].style.display = 'none';
			oShadow[i].style.left = '0px';
			oShadow[i].style.top = '0px';
		}											
	}
}
复制代码

监视鼠标移动位置

接下来添加裁剪区域拉伸的功能,当鼠标移动到边沿的点状边框时呈现不同的效果

添加鼠标显示效果
// 点状边框监视 设置相应操作
oTailor.onmousemove = function(ev) {
	var oTarget = oEvent.target;	
	switch(oTarget.id) {
		case 'box_1':							// 左上

			setAssign(oTailor , 'cursor' , 'nw-resize');				

			break;
		case 'box_2':							// 右上  

			setAssign(oTailor , 'cursor' , 'ne-resize');				

			break;
		case 'box_3':							// 左下
			
			setAssign(oTailor , 'cursor' , 'sw-resize');
			
			break;
		case 'box_4':							// 右下
			setAssign(oTailor , 'cursor' , 'se-resize');
			
			break;
		case 'box_5':							// 上			
			setAssign(oTailor , 'cursor' , 'n-resize');
			
			break;
		case 'box_6':							// 左
			setAssign(oTailor , 'cursor' , 'w-resize');
			
			break;
		case 'box_7':							// 下			
			setAssign(oTailor , 'cursor' , 's-resize');
			
			break;
		case 'box_8':							// 右			
			setAssign(oTailor , 'cursor' , 'e-resize');
			
			break;
		default :								// 裁剪区域 显示可移动提示
			setAssign(oTailor , 'cursor' , 'move');
			break;
	}
}
复制代码

由于监视的div较多,因此采用事件委托的方式添加,效果不方便演示,有兴趣的同学可以自己测试,

添加拉伸效果
代码
// 裁剪区域的移动事件
oTailor.onmousedown = function(ev) {
	// event事件对象
	var oEvent = ev || window.event;
	// 获取cursor状态
	var oCur = getCss(oTailor , 'cursor');		
	// 鼠标初始位置
	var sTmpX = oEvent.clientX;
	var sTmpY = oEvent.clientY;
	
	// 获取裁剪区域的属性 用一个对象保存起来方便调用
	oAttrs.left = getCss(oTailor , 'left');
	oAttrs.top = getCss(oTailor , 'top');
	oAttrs.width = getCss(oTailor , 'width');
	oAttrs.height = getCss(oTailor , 'height');		

	document.onmousemove = function(ev) {
		// 移动事件对象
		var oEvent = ev || window.event;
		// 当前鼠标位置减去初始鼠标位置 等于 鼠标移动距离
		var sLeftT = oEvent.clientX - sTmpX;
		var sTopT = oEvent.clientY - sTmpY ;
		
		// 表示鼠标移动的距离
		var oTmpHeight = '';
		var oTmpTop = '';
		var oTmpWidth = '';
		var oTmpLeft = '';

		switch(oCur) {
			case 'nw-resize' : 			// 左上

				oTmpWidth = parseInt(oAttrs.width) - sLeftT ; 
				oTmpHeight = parseInt(oAttrs.height) - sTopT ; 
				oTmpLeft = parseInt(oAttrs.left) + sLeftT ; 
				oTmpTop = parseInt(oAttrs.top) + sTopT ; 									

				break;
			case 'ne-resize' : 			// 右上
				// 此时width不能减去鼠标移动距离 因为此时移动距离为正值
				oTmpWidth = parseInt(oAttrs.width) + sLeftT ; 
				oTmpHeight = parseInt(oAttrs.height) - sTopT ; 
				// 右上角移动不需要left值 因为默认响右移动
				oTmpTop = parseInt(oAttrs.top) + sTopT ; 																		

				break;
			case 'sw-resize' : 			// 左下
				// 同右上  height 必须是加上鼠标移动距离
				oTmpWidth = parseInt(oAttrs.width) - sLeftT ; 
				oTmpHeight = parseInt(oAttrs.height) + sTopT ; 
				oTmpLeft = parseInt(oAttrs.left) + sLeftT ; 									

				break;
			case 'se-resize' : 			// 右下
				// 左下与右上的结合 同时去除left与top
				oTmpWidth = parseInt(oAttrs.width) + sLeftT ; 
				oTmpHeight = parseInt(oAttrs.height) + sTopT ; 					

				break;
			case 'n-resize'  : 			// 上

			    oTmpHeight = parseInt(oAttrs.height) - sTopT;
			    oTmpTop = parseInt(oAttrs.top) + sTopT;				

				break;
			case 'w-resize'  : 			// 左
						
				oTmpWidth = parseInt(oAttrs.width) - sLeftT ;
				oTmpLeft =  parseInt(oAttrs.left) + sLeftT;	 

				break;
			case 's-resize'  :  		// 下
				
				oTmpHeight = parseInt(oAttrs.height) + sTopT;

				break;
			case 'e-resize'  : 			// 右
						
				var oTmpWidth  = parseInt(oAttrs.width) + sLeftT;
				
				break;
			default :											
				// 否则是移动裁剪区域
				tailorMove(oEvent , oTailor , oPicture , oShadow);

				break;
		}	

		
		
		// 向上拉到边界
		if(parseInt(getCss(oTailor , 'top')) <= oPicture.offsetTop) {
	    	oTmpHeight = parseInt(getCss(oPicture,'height')) - (oPicture.offsetTop+parseInt(getCss(oPicture,'height'))-parseInt(getCss(oTailor,'top'))-parseInt(getCss(oTailor,'height')));
			oTmpTop = oPicture.offsetTop;
	    }else if(oPicture.offsetTop+parseInt(getCss(oPicture,'height')) <= (parseInt(getCss(oTailor,'top'))+parseInt(getCss(oTailor,'height')))){
			// 向下拉到边界
			oTmpHeight = oPicture.offsetTop+parseInt(getCss(oPicture,'height')) - parseInt(getCss(oTailor,'top'));
		}
		// 向左拉到边界
		if((parseInt(getCss(oTailor , 'left'))) <= oPicture.offsetLeft) {
			oTmpWidth = parseInt(getCss(oPicture,'width')) - (oPicture.offsetLeft+parseInt(getCss(oPicture),'width')-parseInt(getCss(oTailor,'left'))-parseInt(getCss(oTailor,'width')))
			oTmpLeft = oPicture.offsetLeft;
		} else if(parseInt(getCss(oTailor , 'width')) + parseInt(getCss(oTailor,'left')) >= (oPicture.offsetLeft+oPicture.offsetWidth)) {
			// 向右拉到边界		
			oTmpWidth = oPicture.offsetLeft+oPicture.offsetWidth - parseInt(getCss(oTailor,'left'));						
		}

		// 赋值
		if(oTmpWidth){
			setAssign(oTailor , 'width'  , oTmpWidth + 'px');
		}
		if(oTmpHeight) {
			setAssign(oTailor , 'height'  , oTmpHeight + 'px');
		}
		if (oTmpLeft) {
			setAssign(oTailor , 'left'  , oTmpLeft + 'px');
		}
		if (oTmpTop) {
			setAssign(oTailor , 'top'  , oTmpTop + 'px');				
		}			
		
		// 阴影区域绘制
		shadow(oPicture , oTailor , oShadow);

		// 添加裁剪边框
		tailorBorder(oDiv  , oHandle , oTailor);
	};

	// 当松开鼠标时注意取消移动事件
	document.onmouseup = function(ev) {
		// event事件对象
		var oEvent = ev || window.event;

		document.onmousemove = null;			
		oEvent.preventDefault();
	}

	oEvent.preventDefault();	
};
复制代码

拉伸时注意移动距离的计算,特别是向上及向左移动时,要注意同时改变裁剪区域的left、top值,否则它只会向下、向右增大。来具体说一下如何计算:

原理

以鼠标向左上角拉伸为例,鼠标的移动距离与上面所讲的一致,但此时注意计算出的值是一个负数,所以在计算裁剪区域的增加值时,要用原裁剪区的宽度或高度减去该值,同时,增加多少宽度,裁剪区的左偏移值就要减去多少,否则显示的效果是裁剪区域向右增大,如下图:

上图中,绿色区域是拉伸时增加宽、高后的裁剪区域,如果没进行偏移调整后的效果既是这样,黄色区域是进行偏移跳转后的裁剪区域,两个的叠加区就是原来的裁剪区了。

这是左上角拉伸,左下角拉伸即其他与之类似,可依照向上套。

而另一关键,拉伸越界在上面已经说过,就不再叙述了。

裁剪区域的移动

现在来说最后一个功能,裁剪区域的移动。当鼠标移动到裁剪区域内部时,就会触发移动事件,此时可以移动裁剪区域,代码如下:

/*  裁剪区域的移动  */
function tailorMove(ev ,oTailor , oPicture ,oShadow) {
	var oEvent = ev || window.event;

	var oTmpx = oEvent.clientX - oTailor.offsetLeft;
	var oTmpy = oEvent.clientY - oTailor.offsetTop;		

	document.onmousemove = function(ev) {
		var oEvent = ev || window.event;							

		oLeft = oEvent.clientX - oTmpx;
		oTop = oEvent.clientY - oTmpy;	

					
		if(oLeft < oPicture.offsetLeft ) {
			oLeft = oPicture.offsetLeft ;	
		} else if(oLeft > (oPicture.offsetLeft + oPicture.offsetWidth - oTailor.offsetWidth)) {
			oLeft = oPicture.offsetLeft + oPicture.offsetWidth - oTailor.offsetWidth;
		}			
		if(oTop < oPicture.offsetTop) {
			oTop = oPicture.offsetTop;	
		} else if (oTop > (oPicture.offsetTop + oPicture.offsetHeight - oTailor.offsetHeight)) {
			oTop = oPicture.offsetTop + oPicture.offsetHeight - oTailor.offsetHeight;
		}				

		oTailor.style.left = ( oLeft)+ 'px';
		oTailor.style.top = (oTop) + 'px';		
		shadow(oPicture , oTailor , oShadow);
	}
}
复制代码

获取裁剪的位置

裁剪效果的功能基本完成,那么就要获取裁剪的位置,首先要知道需要获取那些属性。根据PHPGD库操作,进行图片裁剪需要知道,裁剪的起点坐标以及裁剪的宽高。我用一个函数来获取这些数据,并将其封装后返回:

function getEle() {
	var oPicture = $('img').get(0);
	var oTailor = $('.img_box').get(0);
		
	oAttrs.LeftX = (parseInt(getCss(oTailor,'left')) - oPicture.offsetLeft);
	oAttrs.LeftY = (parseInt(getCss(oTailor,'top')) - oPicture.offsetTop);
	oAttrs.Twidth = (parseInt(getCss(oTailor,'width')));
	oAttrs.Theight = (parseInt(getCss(oTailor,'height')));
	return oAttrs;
}
复制代码

还有一个问题,如果网页上的图片是使用css压缩后的图片,那么在此获得的位置与裁剪大小会与你想像的有区别,可能裁剪后的图片范围会变大(原图较大),也有可能会变小(原图较小)。

如果能够获得原图的大小,可以根据压缩图与原图的比例来进行裁剪,这样可以获得正确的裁剪图。

好了,一个简单的图片裁剪功能就完成了,可以利用ajax传递到后台进行处理了。

时间仓促,在写这篇日志的时候,也发现了不少bug,如,对裁剪越界的处理,当裁剪到即将越界区域,也就是裁剪区域到了图片的边界时,不仅越界的一边无法拉伸,非越界的一边也不能拉伸。以后有时间才进行修改吧。

我非专业前端,且该功能完全由自己独立完成,所以js编写时,可能不太专业,还请见谅。

Jcrop官网下载 (需fanqiang) Jcrop下载 Jcrop文档 Jcrop的GitHub地址

转载于:https://juejin.im/post/5a30f2da518825569539a4b4

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现在所有浏览器兼容的JavaScript裁剪图片功能,可以使用`<canvas>`元素和`CanvasRenderingContext2D` API。以下是一个示例代码: ```html <!DOCTYPE html> <html> <head> <script> function cropImage() { // 获取img元素的引用 var img = document.getElementById('myImage'); // 创建canvas元素和绘图上下文 var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); // 设置canvas的宽度和高度与img相同 canvas.width = img.width; canvas.height = img.height; // 在canvas上绘制原始图片 ctx.drawImage(img, 0, 0); // 裁剪图片的区域(示例:裁剪左上角200x200的区域) var cropX = 0; var cropY = 0; var cropWidth = 200; var cropHeight = 200; // 获取裁剪后的图像数据 var imageData = ctx.getImageData(cropX, cropY, cropWidth, cropHeight); // 创建新的canvas元素和绘图上下文 var croppedCanvas = document.createElement('canvas'); var croppedCtx = croppedCanvas.getContext('2d'); // 设置裁剪后canvas的宽度和高度 croppedCanvas.width = cropWidth; croppedCanvas.height = cropHeight; // 将裁剪后的图像数据绘制到新的canvas上 croppedCtx.putImageData(imageData, 0, 0); // 获取裁剪后的图像URL var croppedImageUrl = croppedCanvas.toDataURL(); // 创建新的img元素来显示裁剪后的图像 var croppedImage = document.createElement('img'); croppedImage.src = croppedImageUrl; // 显示裁剪后的图像 document.body.appendChild(croppedImage); } </script> </head> <body> <img id="myImage" src="path/to/your/image.jpg" alt="Your Image"> <br> <button onclick="cropImage()">裁剪图片</button> </body> </html> ``` 在这个示例,我们首先创建了一个`<canvas>`元素和一个绘图上下文对象。然后,我们将原始图片绘制到canvas上,并使用`getImageData()`方法获取裁剪区域的像素数据。接下来,我们创建了一个新的`<canvas>`元素和一个新的绘图上下文对象,然后使用`putImageData()`方法将裁剪后的图像数据绘制到新的canvas上。最后,我们将裁剪后的图像显示在一个新的`<img>`元素。 请注意,示例的路径`path/to/your/image.jpg`需要替换为你自己的图片路径。此外,你可以根据需要调整裁剪区域的坐标和尺寸来实现不同的裁剪效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值