基于原生JS實(shí)現(xiàn)圖片裁剪
下面是我自己寫的圖片裁剪的功能介紹:
可以利用鼠標(biāo)拖拉,產(chǎn)生裁剪框
可以改變裁剪框大小
點(diǎn)擊確定,返回裁剪數(shù)據(jù)
原理
完成裁剪的方法有兩種:
1、利用HTML5新增拖拽事件drag drop等
2、傳統(tǒng)方法,利用鼠標(biāo)事件,mousedown、mousemove等
在這里,我們采用方法2。
裁剪區(qū)域的形成
要進(jìn)行裁剪首先要形成裁剪區(qū)域,這個裁剪區(qū)域的形成我們可以與鼠標(biāo)移動的距離相關(guān)聯(lián)。鼠標(biāo)移動多遠(yuǎn),裁剪區(qū)域就有多大。如下圖:

如上圖所示鼠標(biāo)的橫向移動距離與縱向移動距離共同組成了裁剪區(qū)域的寬和高。
而這橫向與縱向移動的距離如何計算呢?當(dāng)我們點(diǎn)下鼠標(biāo)時,就能夠通過event事件對象獲取鼠標(biāo)點(diǎn)擊位置,而移動鼠標(biāo)時,也能夠通過event獲取鼠標(biāo)的位置,通過兩次鼠標(biāo)位置的改變,就能夠獲得鼠標(biāo)的移動距離。
獲取鼠標(biāo)位置的屬性是clientX以及clientY
陰影區(qū)域的形成
接下來就是繪制陰影區(qū)域。被裁剪圖片中除裁剪區(qū)域以外的部分,都屬于陰影部分,也可以不繪制該區(qū)域,繪制該區(qū)域是為了讓用戶更清晰的看清裁剪區(qū)域。
我將該區(qū)域分成了上下左右四個部分,見下圖分布:

那么該區(qū)域如果計算呢?這時就要用到Dom元素的偏移值了,利用裁剪區(qū)域的左偏移值減去圖片本身的左偏移值就是左陰影的寬,利用裁剪區(qū)域的上偏移值減去圖片的上偏移值,等于上陰影的高度值。如下圖:
獲取到左陰影、上陰影的值后,就能夠通過這兩個將其他陰影的屬性計算出來。
圖片的偏移值有兩種取法
1.利用offsetLeft 與 offsetTop 值 弊端 如果dom元素有border margin等值會將這些值計算在內(nèi)
2.獲取dom的css屬性 弊端 預(yù)定義的css有關(guān) 如果沒定義left top就無法獲取
這兩種方法都有各自的弊端,視不同情況來使用
裁剪越界的阻止
裁剪區(qū)域的計算是通過鼠標(biāo)的移動距離來計算的,因此會出現(xiàn)裁剪區(qū)域越界的情況,而這情況又分成兩種:
1.裁剪過程中越界
2.移動裁剪區(qū)域時越界
那么下面就來說說如何防止越界。
裁剪越界
什么是裁剪時越界?就是鼠標(biāo)拖動區(qū)域超出了圖片的返回,形成了越界,如下圖:

對于這種越界需要判斷裁剪區(qū)域的右側(cè)相對于瀏覽器左側(cè)的位置 不能夠超過 圖片右側(cè)的位置相當(dāng)于瀏覽器左側(cè)的位置;同時裁剪區(qū)域底部相對于瀏覽器頂部位置 不能夠超過 圖片底部相對應(yīng)瀏覽器頂部的位置。還是畫圖來說明:

當(dāng)TX >= PX 時就讓TX的值強(qiáng)制為一固定值。
TX與PX的計算方法,假設(shè)裁剪區(qū)域?yàn)?code>oTailor,圖片區(qū)域oPicture:
TX = oTailor.offsetWidth + oTailor.offsetLeft; PX = oPicture.offsetWidth + oPicture.offsetLeft;
同理,可以按照上述方法對左側(cè)越界,上側(cè)越界,下側(cè)越界進(jìn)行限制,就不多贅述。
移動越界
移動越界指的是已經(jīng)形成了裁剪區(qū)域了,但通過鼠標(biāo)移動裁剪區(qū)域時產(chǎn)生了越界。這個理解比較簡單,就不畫圖介紹了。這種越界與dom拖拽越界限制一致,通過判斷鼠標(biāo)移動距離是否超過了圖片區(qū)域來判斷。
原理與問題解決了,現(xiàn)在開始來完成實(shí)際功能。
準(zhǔn)備工作
在做之前,先做一些準(zhǔn)備工作,磨刀不誤砍柴功。
網(wǎng)頁布局準(zhǔn)備
網(wǎng)頁布局部分關(guān)鍵代碼如下:
<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表示的是裁剪區(qū)域,outer表示陰影區(qū)域,而img_box中的div是裁剪區(qū)域的邊框
樣式控制如下:
* {
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;
}
布局效果如下:

通用函數(shù)
完成圖片裁剪,通過上述原理,可以知道需要大量獲取標(biāo)簽對象以及標(biāo)簽的css屬性等,所以可以編寫通用函數(shù),更好的獲取這些值。如下:
Dom獲取函數(shù)
/* 仿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屬性獲取函數(shù)
Css屬性的獲取分成兩種,一種是IE的,使用currentStyle;另一種是其他主流瀏覽器,使用getComputedStyle,以下是兼容版本:
/* Css獲取 */
function getCss(o , key){
return o.currentStyle? o.currentStyle[key] : document.defaultView.getComputedStyle(o,false)[key];
};
賦值函數(shù)
編寫時經(jīng)常遇到對Dom的樣式進(jìn)行賦值,為方便,我專門編寫了一個函數(shù)用于賦值:
/**
- 賦值函數(shù)
- @param : obj 被賦值對象
- @param : option 進(jìn)行的操作
- @parma : value 賦值內(nèi)容
*/
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;
}
}
好了準(zhǔn)備工作基本完成,現(xiàn)在就正式開始編寫。
通過點(diǎn)擊與移動事件完成裁剪區(qū)域繪制
對圖片設(shè)置mousedown以及mousemove事件監(jiān)視,如下:
// 鼠標(biāo)點(diǎn)擊圖片觸發(fā)
oPicture.onmousedown = function(ev) {
// 事件對象
var oEvent = ev || window.event;
// 初始鼠標(biāo)位置
var tempX = oEvent.clientX;
var tempY = oEvent.clientY;
// 調(diào)整裁剪區(qū)域位置
oTailor.style.left = oEvent.clientX + 'px';
oTailor.style.top = oEvent.clientY + 'px';
// 鼠標(biāo)在圖片上移動 繪制裁剪區(qū)域 陰影區(qū)域
document.onmousemove = function(ev) {
// 鼠標(biāo)移動事件對象
var oEvent = ev || window.event;
// 當(dāng)前鼠標(biāo)位置減去鼠標(biāo)之前的鼠標(biāo)位置 等于 鼠標(biāo)移動距離
var sLeft = oEvent.clientX - tempX;
var sTop = oEvent.clientY - tempY;
// 裁剪越界限制 只需限制右側(cè) 與 下側(cè)
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;
}
// 裁剪區(qū)域繪制
oTailor.style.width = sLeft + 'px';
oTailor.style.height = sTop + 'px';
// 裁剪區(qū)域顯示
oTailor.style.display = 'block';
// 陰影區(qū)域顯示
for (var i = 0; i < oShadow.length; i++) {
oShadow[i].style.display = 'block';
}
// 陰影區(qū)域繪制
shadow(oPicture , oTailor , oShadow);
// 添加裁剪邊框
tailorBorder(oDiv , oHandle , oTailor);
// 阻止默認(rèn)事件
oEvent.preventDefault();
};
// 鼠標(biāo)松開 將移動事件取消
document.onmouseup = function(ev) {
var oEvent = ev || window.event;
// 移動事件取消
document.onmousemove = null;
// 阻止默認(rèn)事件
oEvent.preventDefault();
};
// 阻止默認(rèn)事件
oEvent.preventDefault();
}
陰影區(qū)域繪制
/**
* @param:oPicture 圖片dom對象
* @param:oTailor 裁剪區(qū)域dom對象
* @param:oShadow 陰影區(qū)域dom對象
*/
function shadow(oPicture , oTailor , oShadow) {
// 左側(cè)陰影區(qū)
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')
//右側(cè)陰影區(qū)
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');
// 上側(cè)陰影區(qū)
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');
// 下側(cè)陰影區(qū)
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');
}
注意在網(wǎng)頁實(shí)際運(yùn)用中,如果布局中圖片css中沒有l(wèi)eft或top屬性,那么上面代碼會產(chǎn)生錯誤。應(yīng)該使用offsetLeft與offsetTop代替之。
添加裁剪邊框
在放出的布局圖中,可以看見裁剪的邊沿,四角及四邊各有一個小正方形的形狀,添加不僅是為了區(qū)分裁剪區(qū)與非裁剪區(qū),還為下一步添加拉伸裁剪區(qū)域提供方便。下面開始編寫代碼:
/**
* 裁剪邊框繪制
* @param : oDIv 所有邊框?qū)ο?
* @param : oHandle 點(diǎn)狀邊沿
* @param : oTailor 裁剪對象
*/
function tailorBorder(oDiv , oHandle , oTailor) {
// 對邊框進(jìn)行初始化
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');
}
/* 點(diǎn)狀邊沿繪制 */
// 四角點(diǎn)狀邊沿繪制
for (var i = 0; i < 4; i++) {
// 點(diǎn)狀繪制
setAssign(oHandle[i] , 'position' , 'absolute');
setAssign(oHandle[i] , 'width' , '5px');
setAssign(oHandle[i] , 'height' , '5px');
// 0 2 表示左側(cè)點(diǎn)狀
if(i % 2 == 0) {
setAssign(oHandle[i] , 'left' , '0px');
setAssign(oHandle[i] , 'top' , (i == 0?'0px' : (parseInt(getCss(oTailor , 'height')) - 8) + 'px'));
} else {
// 右側(cè)點(diǎn)狀
setAssign(oHandle[i] , 'left' , ( parseInt(getCss(oTailor , 'width')) - 6 ) + 'px');
setAssign(oHandle[i] , 'top' , (i == 1?'0px' : parseInt(getCss(oTailor , 'height')) - 8 ) + 'px');
}
}
// 四邊點(diǎn)狀邊框
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 表示上 下 點(diǎn)狀邊框
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 {
// 左右點(diǎn)狀
setAssign(oHandle[i] , 'top' , parseInt(getCss(oTailor , 'height')) / 2 + 'px');
setAssign(oHandle[i] , 'left' ,(i == 5 ? '0px' : parseInt(getCss(oTailor , 'width')) - 8 ) + 'px');
}
}
}
布局中,裁剪區(qū)域類名為box_handle的div前四個代表四角的點(diǎn)狀,后四個表示邊沿中間的點(diǎn)狀,都按照順時針分布。完成后效果如下:

監(jiān)視陰影區(qū)域
裁剪區(qū)域與陰影區(qū)域繪制完成,現(xiàn)在添加一個小功能,當(dāng)鼠標(biāo)點(diǎn)擊到非裁剪區(qū)時(即陰影區(qū)),取消裁剪區(qū)域。
// 對陰影區(qū)域設(shè)置時間 點(diǎn)擊到陰影區(qū)時 裁剪區(qū)域消失 陰影區(qū)消失
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';
}
}
}
監(jiān)視鼠標(biāo)移動位置
接下來添加裁剪區(qū)域拉伸的功能,當(dāng)鼠標(biāo)移動到邊沿的點(diǎn)狀邊框時呈現(xiàn)不同的效果
添加鼠標(biāo)顯示效果
// 點(diǎn)狀邊框監(jiān)視 設(shè)置相應(yīng)操作
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 : // 裁剪區(qū)域 顯示可移動提示
setAssign(oTailor , 'cursor' , 'move');
break;
}
}
由于監(jiān)視的div較多,因此采用事件委托的方式添加,效果不方便演示,有興趣的同學(xué)可以自己測試,
添加拉伸效果
代碼
// 裁剪區(qū)域的移動事件
oTailor.onmousedown = function(ev) {
// event事件對象
var oEvent = ev || window.event;
// 獲取cursor狀態(tài)
var oCur = getCss(oTailor , 'cursor');
// 鼠標(biāo)初始位置
var sTmpX = oEvent.clientX;
var sTmpY = oEvent.clientY;
// 獲取裁剪區(qū)域的屬性 用一個對象保存起來方便調(diào)用
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;
// 當(dāng)前鼠標(biāo)位置減去初始鼠標(biāo)位置 等于 鼠標(biāo)移動距離
var sLeftT = oEvent.clientX - sTmpX;
var sTopT = oEvent.clientY - sTmpY ;
// 表示鼠標(biāo)移動的距離
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不能減去鼠標(biāo)移動距離 因?yàn)榇藭r移動距離為正值
oTmpWidth = parseInt(oAttrs.width) + sLeftT ;
oTmpHeight = parseInt(oAttrs.height) - sTopT ;
// 右上角移動不需要left值 因?yàn)槟J(rèn)響右移動
oTmpTop = parseInt(oAttrs.top) + sTopT ;
break;
case 'sw-resize' : // 左下
// 同右上 height 必須是加上鼠標(biāo)移動距離
oTmpWidth = parseInt(oAttrs.width) - sLeftT ;
oTmpHeight = parseInt(oAttrs.height) + sTopT ;
oTmpLeft = parseInt(oAttrs.left) + sLeftT ;
break;
case 'se-resize' : // 右下
// 左下與右上的結(jié)合 同時去除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 :
// 否則是移動裁剪區(qū)域
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');
}
// 陰影區(qū)域繪制
shadow(oPicture , oTailor , oShadow);
// 添加裁剪邊框
tailorBorder(oDiv , oHandle , oTailor);
};
// 當(dāng)松開鼠標(biāo)時注意取消移動事件
document.onmouseup = function(ev) {
// event事件對象
var oEvent = ev || window.event;
document.onmousemove = null;
oEvent.preventDefault();
}
oEvent.preventDefault();
};
拉伸時注意移動距離的計算,特別是向上及向左移動時,要注意同時改變裁剪區(qū)域的left、top值,否則它只會向下、向右增大。來具體說一下如何計算:
原理
以鼠標(biāo)向左上角拉伸為例,鼠標(biāo)的移動距離與上面所講的一致,但此時注意計算出的值是一個負(fù)數(shù),所以在計算裁剪區(qū)域的增加值時,要用原裁剪區(qū)的寬度或高度減去該值,同時,增加多少寬度,裁剪區(qū)的左偏移值就要減去多少,否則顯示的效果是裁剪區(qū)域向右增大,如下圖:

上圖中,綠色區(qū)域是拉伸時增加寬、高后的裁剪區(qū)域,如果沒進(jìn)行偏移調(diào)整后的效果既是這樣,黃色區(qū)域是進(jìn)行偏移跳轉(zhuǎn)后的裁剪區(qū)域,兩個的疊加區(qū)就是原來的裁剪區(qū)了。
這是左上角拉伸,左下角拉伸即其他與之類似,可依照向上套。
而另一關(guān)鍵,拉伸越界在上面已經(jīng)說過,就不再敘述了。
裁剪區(qū)域的移動
現(xiàn)在來說最后一個功能,裁剪區(qū)域的移動。當(dāng)鼠標(biāo)移動到裁剪區(qū)域內(nèi)部時,就會觸發(fā)移動事件,此時可以移動裁剪區(qū)域,代碼如下:
/* 裁剪區(qū)域的移動 */
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);
}
}
獲取裁剪的位置
裁剪效果的功能基本完成,那么就要獲取裁剪的位置,首先要知道需要獲取那些屬性。根據(jù)PHP的GD庫操作,進(jìn)行圖片裁剪需要知道,裁剪的起點(diǎn)坐標(biāo)以及裁剪的寬高。我用一個函數(shù)來獲取這些數(shù)據(jù),并將其封裝后返回:
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;
}
還有一個問題,如果網(wǎng)頁上的圖片是使用css壓縮后的圖片,那么在此獲得的位置與裁剪大小會與你想像的有區(qū)別,可能裁剪后的圖片范圍會變大(原圖較大),也有可能會變小(原圖較小)。
如果能夠獲得原圖的大小,可以根據(jù)壓縮圖與原圖的比例來進(jìn)行裁剪,這樣可以獲得正確的裁剪圖。
好了,一個簡單的圖片裁剪功能就完成了,可以利用ajax傳遞到后臺進(jìn)行處理了。
本文內(nèi)容到此就結(jié)束了,有問題的話歡迎大家留言討論,希望本文對大家學(xué)習(xí)javascript有所幫助。
- js+jquery實(shí)現(xiàn)圖片裁剪功能
- php+js實(shí)現(xiàn)圖片的上傳、裁剪、預(yù)覽、提交示例
- 基于HTML5+JS實(shí)現(xiàn)本地圖片裁剪并上傳功能
- Cropper.js 實(shí)現(xiàn)裁剪圖片并上傳(PC端)
- 使用ImageMagick進(jìn)行圖片縮放、合成與裁剪(js+python)
- 使用JavaScript+canvas實(shí)現(xiàn)圖片裁剪
- vue-cli結(jié)合Element-ui基于cropper.js封裝vue實(shí)現(xiàn)圖片裁剪組件功能
- Nodejs下使用gm圓形裁剪并合成圖片的示例
- cropper js基于vue的圖片裁剪上傳功能的實(shí)現(xiàn)代碼
- cropperjs實(shí)現(xiàn)裁剪圖片功能
相關(guān)文章
原生JS操作網(wǎng)頁給p元素添加onclick事件及表格隔行變色
原生JS操作網(wǎng)頁,給網(wǎng)頁中的所有p元素添加onclick事件,使一個特定的表格隔行變色等等,感興趣的朋友可以參考下2013-12-12
判斷目標(biāo)是否是window,document,和擁有tagName的Element的代碼
判斷目標(biāo)是否是window,document,和擁有tagName的Element的代碼,需要的朋友可以參考下。2010-05-05
微信小程序天氣預(yù)報功能實(shí)現(xiàn)(支持自動定位,附源碼)
對于一個經(jīng)常出門在外的人,關(guān)注天氣是至關(guān)重要的,下面這篇文章主要給大家介紹了關(guān)于微信小程序天氣預(yù)報功能實(shí)現(xiàn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),支持自動定位,需要的朋友可以參考下2022-04-04
一文教你徹底學(xué)會JavaScript手寫防抖節(jié)流
其實(shí)防抖和節(jié)流不僅僅在面試中會讓大家手寫,在實(shí)際項目中也可以起到性能優(yōu)化的作用,所以還是很有必要掌握的。本文就帶大家徹底學(xué)會JavaScript手寫防抖節(jié)流,需要的可以參考一下2022-11-11
JS實(shí)現(xiàn)的隨機(jī)排序功能算法示例
這篇文章主要介紹了JS實(shí)現(xiàn)的隨機(jī)排序功能算法,結(jié)合具體實(shí)例形式分析了javascript常用的排序算法實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-06-06
JS實(shí)現(xiàn)可拖曳、可關(guān)閉的彈窗效果
這篇文章主要介紹了JS實(shí)現(xiàn)可拖曳、可關(guān)閉的彈窗效果,可實(shí)現(xiàn)點(diǎn)擊文字彈出可拖動的窗口,同時背景出現(xiàn)變暗的遮罩效果,點(diǎn)擊遮罩層即可關(guān)閉彈出,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09
從QQ網(wǎng)站中提取的純JS省市區(qū)三級聯(lián)動菜單
在瀏覽網(wǎng)頁過程中發(fā)現(xiàn)QQ自己的JS省市區(qū)三級聯(lián)動。所以研究了一下,就將其提取出來了。他的界面如下,喜歡的朋友可以學(xué)習(xí)下2013-12-12


