Vue-cropper 圖片裁剪的基本原理及思路講解
一:裁剪的思路:
1-1,裁剪區(qū)域:需要進(jìn)行裁剪首先需要形成裁剪區(qū)域,裁剪區(qū)域的大小和我們的鼠標(biāo)移動(dòng)的距離相關(guān)聯(lián),鼠標(biāo)移動(dòng)有多遠(yuǎn),裁剪區(qū)域就有多大。如下圖:
1-2 裁剪區(qū)域的寬和高的計(jì)算:
如上圖,鼠標(biāo)的橫向移動(dòng)距離和縱向移動(dòng)距離就形成了裁剪區(qū)域的寬和高。那么裁剪區(qū)域的寬和高的計(jì)算是:當(dāng)我們點(diǎn)下鼠標(biāo)時(shí),就能夠通過(guò)event事件
對(duì)象獲取鼠標(biāo)點(diǎn)擊位置,e.clientX 和 e.clientY; 當(dāng)鼠標(biāo)進(jìn)行移動(dòng)的時(shí)候,也能通過(guò)event獲取鼠標(biāo)的位置,通過(guò)兩次鼠標(biāo)位置的改變,就能夠獲得
鼠標(biāo)移動(dòng)的距離。即:初始的x軸位置為 initX = e.clientX, initY = e.clientY;
移動(dòng)到某個(gè)點(diǎn)的位置為:endX = e.clientX, endY = e.clientY;
因此裁剪區(qū)域的寬 Tx = endX - initX;
裁剪區(qū)域的高是 Ty = endY - initY;
1-3 陰影區(qū)域的形成
被我們裁剪圖片中除了裁剪區(qū)域以外的部分,都屬于陰影部分。如下圖所示:
那么陰影區(qū)域要如何計(jì)算呢?比如左陰影寬,左陰影寬 = 裁剪區(qū)域的左偏移值 - 圖片本身的左偏移值;那么上陰影高 = 裁剪區(qū)域的上偏移值 - 圖片上偏移值, 如下圖所示:
那么下陰影的高度 = 圖片本身的高度 - 上陰影的高度 - 裁剪區(qū)域的高度;那么右陰影的寬度 = 圖片的寬度 - 左陰影寬 - 裁剪區(qū)域的寬。
1-4 理解裁剪區(qū)域被越界
裁剪圖片過(guò)程中會(huì)出現(xiàn)越界的情況,那么越界又需要分為2種情況, 第一種是:裁剪過(guò)程中的越界,第二種是 移動(dòng)裁剪區(qū)域的越界。
1-4-1 裁剪越界
什么是裁剪時(shí)越界? 就是當(dāng)我們使用鼠標(biāo)拖動(dòng)區(qū)域裁剪超出了圖片的寬度和高度,形成了的越界;如下圖所示:
對(duì)于這種越界需要判斷被裁剪區(qū)域的右側(cè)相對(duì)于瀏覽器左側(cè)的位置,不能超過(guò)圖片右側(cè)的位置相對(duì)于瀏覽器左側(cè)的位置;
且 被裁剪區(qū)域的底部相對(duì)于瀏覽器頂部的位置 不能超過(guò) 圖片的底部相對(duì)于瀏覽器頂部的位置,如下圖所示:
1-4-2 移動(dòng)越界
移動(dòng)越界指已經(jīng)形成了裁剪區(qū)域了,但是我們可以通過(guò)鼠標(biāo)裁剪區(qū)域時(shí)產(chǎn)生了越界。其實(shí)判斷原理和裁剪越界的原理一樣的。
2. 圖片如何進(jìn)行壓縮?
當(dāng)圖片的寬度大于容器的寬度,就需要進(jìn)行壓縮;因此 var scale = 容器的寬度 / 圖片的寬度;
如果圖片的高度 * 縮放比例 > 容器的高度,那么縮放比例 scale = 容器的高度 / 圖片的高度;否則的話(huà),不進(jìn)行壓縮。
2-1:對(duì)于壓縮后 translate3d中的X軸和Y軸移動(dòng)位置計(jì)算方式:
x = 容器的寬度 / 壓縮比
y = 容器的高度 / 壓縮比
即:transform: translate3d(x, y, z) -> translate3d(容器的寬度 / 壓縮比 + 'px', 容器的高度 / 壓縮比 + 'px', 0)
因此頁(yè)面布局變成如下:
<!DOCTYPE html> <html> <head> <title>圖片裁剪</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"> <link rel="stylesheet" type="text/css" href="./index.css"> </head> <body> <div id="app" style="height:500px;margin: 0 auto;"> <div class="vue-cropper"> <div class="cropper-box"> <div class="cropper-box-canvas" style="width:644px;height:642px;transform: scale(0.778816, 0.778816) translate3d(453.252px, -87.312px, 0px) rotateZ(0deg)"> <img src="https://images2018.cnblogs.com/blog/561794/201804/561794-20180416230443389-1451524334.jp" /> </div> </div> <div class="cropper-drag-box cropper-crop"></div> </div> </div> </body> </html>
4. 裁剪的過(guò)程中,如何計(jì)算裁剪的寬度和高度?
當(dāng)我們點(diǎn)下鼠標(biāo)時(shí),就能夠通過(guò)event事件對(duì)象獲取鼠標(biāo)點(diǎn)擊位置,e.clientX 和 e.clientY; 當(dāng)鼠標(biāo)進(jìn)行移動(dòng)的時(shí)候,也能通過(guò)event獲取鼠標(biāo)的位置,
通過(guò)兩次鼠標(biāo)位置的改變,就能夠獲得鼠標(biāo)移動(dòng)的距離。即:
初始的x軸和Y軸位置分別為 cropX = e.clientX, cropY = e.clientY;
移動(dòng)后現(xiàn)在的X軸和Y軸的位置分別為:nowX = e.clientX, nowY = e.clientY;
因此裁剪區(qū)域的臨時(shí)值 var fw = ~~(nowX - cropX);
裁剪區(qū)域的臨時(shí)值是 fh = ~~(nowY - cropY);
裁剪圖片的時(shí)候,有可能往右拖動(dòng)(值會(huì)越來(lái)越大),也有可能往相反的方向(向左)拖動(dòng)(值會(huì)越來(lái)越小),同理,向上或向下拖動(dòng)也是同一個(gè)道理。因此需要判斷 fw 和 fh是否大于0的判斷;在鼠標(biāo)按鍵下去的時(shí)候,先獲取鼠標(biāo)相對(duì)于事件源元素的X和Y軸坐標(biāo),e.offsetX 和 e.offsetY;
因此 cropChangeX = e.offsetX; cropChangeY = e.offsetY;
對(duì)于offsetX 和 offsetY 的理解如下;
if (fw > 0) { var cropW(裁剪區(qū)域的實(shí)際寬度) = cropChangeX + fw > w(圖片的實(shí)際寬度) ? w - cropChangeX : fw; cropOffsertX = cropChangeX; }
cropOffsertX 就是保存事件源相對(duì)于元素的距離。
如果fw 小于0,說(shuō)明是往左裁剪,那么裁剪的距離 fw = (事件結(jié)束的clientX - 事件的開(kāi)始clientX);
如果 (圖片的實(shí)際寬度 - e.offsetX) + Math.abs(fw) > 圖片的實(shí)際寬度 ? this.cropChangeX : Math.abs(fw);
即:
if (fw < 0) { var cropW(裁剪區(qū)域的實(shí)際寬度) = (w - cropChangeX) + Math.abs(fw) > w ? cropChangeX : Math.abs(fw); cropOffsertX = cropChangeX + fw > 0 ? cropChangeX + fw : 0; }
說(shuō)明往左裁剪的最大寬度只能是 e.offsetX; 不能超過(guò)該值,否則的話(huà),就會(huì)越界。
此時(shí)cropOffsertX偏移值改變了; cropOffsertX = cropChangeX + fw > 0 ? cropChangeX + fw : 0
; 如圖下所示:
上面分析的是 寬和高不固定比例的裁剪,下面我們來(lái)看下 寬和高固定比例的裁剪。
5. 寬和高固定比例裁剪計(jì)算;
比如寬和高比是 3:4 這樣的截圖;fixedNumber = [3, 4]
因此 固定比例高度的計(jì)算
fixedHeight 裁剪區(qū)域的實(shí)際寬度
------------- = ---------------
fixedNumber[1] fixedNumber[0]
因此:
var fixedHeight = ~~(裁剪區(qū)域的實(shí)際寬度 / fixedNumber[0] * fixedNumber[1]);
如果固定比例的移動(dòng)的高度 + Y軸上相對(duì)于圖片的偏移值 > 大于圖片的高度的話(huà),那么裁剪區(qū)域的高度(cropH) = 圖片的高度(h) - Y軸上相對(duì)于圖片的偏移值(cropOffsertY); 如下圖所示:
獲取到了 裁剪區(qū)域的高度的話(huà),就可以獲取到裁剪區(qū)域的寬度了;計(jì)算方式是:
cropW(裁剪區(qū)域的寬度) = ~~(cropH / fixedNumber[1] * fixedNumber[0]);
同時(shí)也要判斷fw 是否大于0,來(lái)計(jì)算 cropOffsertX 的值;
if (fw > 0) { var cropOffsertX = cropChangeX } else { var cropOffsertX = cropChangeX - cropW }
fw > 0 說(shuō)明是往右移動(dòng),因此 cropOffsertX = cropChangeX;
fw < 0 說(shuō)明是往左移動(dòng),cropOffsertX = 初始的 e.offsetX - 裁剪區(qū)域的寬度
即:
if (fw > 0) { var cropOffsertX = cropChangeX } else { var cropOffsertX = cropChangeX - cropW } fw > 0 說(shuō)明是往右移動(dòng),因此 cropOffsertX = cropChangeX; fw < 0 說(shuō)明是往左移動(dòng),cropOffsertX = 初始的 e.offsetX - 裁剪區(qū)域的寬度 即: if (fixedHeight + cropOffsertY > h) { cropH(裁剪區(qū)域的高度) = h - cropOffsertY; cropW(裁剪區(qū)域的寬度) = ~~(cropH / fixedNumber[1] * fixedNumber[0]); if (fw > 0) { var cropOffsertX = cropChangeX } else { var cropOffsertX = cropChangeX - cropW } } else { // 否則 cropH = fixedHeight; }
6. 理解裁剪區(qū)域拉伸原理
控制裁剪區(qū)域拉伸的點(diǎn),共有12種可以拉伸的點(diǎn),分別有裁剪區(qū)域的四根線(xiàn)可以拉伸,有四根線(xiàn)上的八個(gè)點(diǎn)可以拉伸;如下圖所示:
當(dāng)鼠標(biāo)點(diǎn)擊拉伸的時(shí)候,會(huì)觸發(fā)mousedown事件;因此需要區(qū)分下到底是那根線(xiàn)或那個(gè)點(diǎn)向什么方向拉伸。因此定義 canChangeX 和 canChangeY 兩個(gè)變量,
判斷是否能改變X軸和Y軸;默認(rèn)是false;同時(shí)定義兩個(gè)變量為 changeCropTypeX 和 changeCropTypeY,含義是能否改變x軸或Y軸的基準(zhǔn)點(diǎn)。默認(rèn)為1;可以改變。
1. 裁剪區(qū)域的最上面的線(xiàn); 可以上下拉伸, 不能左右拉伸;
因此可以約定: canChangeX = false, canChangeY = true; changeCropTypeX = 0; changeCropTypeY = 1;
2. 裁剪區(qū)域左邊的線(xiàn);可以左右拉伸,不能上下拉伸;
因此可以約定:canChangeX = true, canChangeY = false; changeCropTypeX = 1; changeCropTypeY = 0;
3. 裁剪區(qū)域底部線(xiàn); 可以上下拉伸,不能左右拉伸;
因此可以約定:canChangeX = false; canChangeY = true; changeCropTypeX = 0; changeCropTypeY = 2;(為了區(qū)分上面的線(xiàn),因此等于2);
4. 裁剪區(qū)域右邊線(xiàn);可以左右拉伸,不能上下拉伸;
因此可以約定:canChangeX = true; canChangeY = false; changeCropTypeX = 2;(為了區(qū)分左邊的線(xiàn)) changeCropTypeY = 0;
5. 左上角的點(diǎn);可以向上或向左移動(dòng);
因此 canChangeX = true, canChangeY = true; changeCropTypeX = 1; changeCropTypeY = 1;
6. 上面中間的點(diǎn),只能上下拉伸,不能左右拉伸;
因此 canChangeX = false, canChangeY = true; changeCropTypeX = 0; changeCropTypeY = 1;
7. 右上角的點(diǎn),可以左右拉伸和上下拉伸;
因此 canChangeX = true, canChangeY = true; changeCropTypeX = 2; changeCropTypeY = 1;
8. 左中角的點(diǎn),只能左右拉伸,不能上下拉伸;
因此 canChangeX = true, canChangeY = false; changeCropTypeX = 1; changeCropTypeY = 0;
9. 右中角的點(diǎn),只能左右拉伸,不能上下拉伸;
因此 canChangeX = true, canChangeY = false; changeCropTypeX = 2; changeCropTypeY = 0;
10. 左下角的點(diǎn),可以向上或向左移動(dòng);
因此 canChangeX = true, canChangeY = true; changeCropTypeX = 1; changeCropTypeY = 2;
11. 下線(xiàn)中間的店,可以上下拉伸,不能左右拉伸;
因此 canChangeX = false, canChangeY = true; changeCropTypeX = 0; changeCropTypeY = 2;
12. 下右角點(diǎn),可以上下拉伸,左右拉伸;
因此 canChangeX = true, canChangeY = true; changeCropTypeX = 2; changeCropTypeY = 2;
下面來(lái)看看移動(dòng)操作;
var fw = ~~(移動(dòng)結(jié)束的clientX - 初始的clientX); var fh = ~~(移動(dòng)結(jié)束的clientY - 初始的clientY);
6-1 向左或向右拉伸的基本原理:
if (canChangeX) { // 如果x軸能改變的話(huà),說(shuō)明是 裁剪區(qū)域中左右兩根線(xiàn)或是左右兩個(gè)線(xiàn)上的點(diǎn)了。 if (changeCropTypeX === 1) { // 如果x軸的基點(diǎn)能改變的話(huà),并且等于1,說(shuō)明是裁剪區(qū)域左邊的線(xiàn)或左邊線(xiàn)上的點(diǎn)了。 // 那就有四種可能值,1. 左邊的線(xiàn),2. 左上角的點(diǎn),3. 左中角的點(diǎn)。 4. 左下角的點(diǎn)。 } else if (changeCropTypeX === 2) { // 同理,說(shuō)明是裁剪區(qū)域右邊的線(xiàn)或右邊線(xiàn)上的點(diǎn)了。 // 那也有四種可能值,1. 右邊的線(xiàn),2. 右上角的點(diǎn),3. 右中角的點(diǎn)。4. 右下角的點(diǎn)。 } }
changeCropTypeX === 1 的情況;繼續(xù)如下判斷:
假設(shè)裁剪區(qū)域的原始寬度為 cropOldW,裁剪區(qū)域的原始高度為 cropOldY, cropChangeX 保存原始的裁剪區(qū)域相對(duì)于圖片的e.offsetX;
if (cropOldW - fw > 0) { 如果裁剪區(qū)域的原始寬度 大于 移動(dòng)的距離的話(huà),那么說(shuō)明兩點(diǎn),第一是向左拉伸的話(huà),fw為負(fù)數(shù),第二是向右拉伸,但是拉伸的距離小于裁剪區(qū)域的原始寬度 裁剪區(qū)域后的寬度 = 圖片的寬度 - 拉伸前的offsetX - 拉伸的距離 <= 圖片的寬度的話(huà) ? 拉伸前的offsetX(cropChangeX) - 拉伸的距離 : 裁剪區(qū)原始寬度 + 拉伸前的offsetX. 裁剪后的 cropOffsertX = 圖片的寬度 - 拉伸前的offsetX(cropChangeX) - 拉伸的距離 <= 圖片的寬度的話(huà) ? 裁剪區(qū)域前的offsertX(cropChangeX) + 拉伸的距離 : 0; }
不管向左拉還是向右拉,裁剪區(qū)后的寬度 都等于 = 拉伸前的offsetX(cropChangeX) - 拉伸的距離;
裁剪后的 cropOffsertX = 裁剪區(qū)域前的offsertX(cropChangeX) + 拉伸的距離; 如下圖所示:
if (cropOldW - fw <= 0) { 裁剪拉伸后的寬度 = 拉伸后的距離fw + cropChangeX <= 圖片的寬度 ? 拉伸后的距離fw - 拉伸前的裁剪區(qū)域的寬度 : 圖片的寬度 - 拉伸前的裁剪區(qū)域的寬度 - cropChangeX; 裁剪拉伸后的 cropOffsertX = 拉伸前的裁剪區(qū)域的offsetX(cropChangeX) + 裁剪區(qū)域之前的寬度; }
如下圖所示:
changeCropTypeX === 2 的情況;
說(shuō)明是裁剪區(qū)域右邊的線(xiàn)或右邊線(xiàn)上的點(diǎn)拉伸了。那也有四種可能值,1. 右邊的線(xiàn),2. 右上角的點(diǎn),3. 右中角的點(diǎn)。4. 右下角的點(diǎn)。
同理;右邊的線(xiàn)拉伸也有向左拉伸和向右拉伸,如果向左拉伸的話(huà),那么fw肯定為負(fù)數(shù),如果向右拉伸的話(huà),那么fw就為正數(shù)。
if (cropOldW + fw > 0) { // 如果原始的裁剪區(qū)域的寬度 + 拉伸的距離大于0,說(shuō)明是向右拉伸或者向左拉伸,但是向左拉伸的距離小于原始裁剪區(qū)域 if (裁剪區(qū)域的原始寬度 + 移動(dòng)距離fw + cropOffsertX <= 圖片的寬度的話(huà)) { }
這里的 裁剪區(qū)域的原始寬度 + 移動(dòng)距離fw + cropOffsertX <= 圖片的寬度的話(huà) 也有兩種情況,第一種是向左拉伸,第二種是向右拉伸,但是沒(méi)有拉伸到底,
也就是說(shuō)拉伸的距離沒(méi)有到圖片的最右邊;
現(xiàn)在的圖片裁剪區(qū)域?qū)挾?cropW) = 圖片的原始區(qū)域的寬度 + fw(拉伸的距離,向左拉伸或向右拉伸);
否則的話(huà),也就是說(shuō)拉伸到最右邊了,那么 圖片裁剪區(qū)域?qū)挾?cropW) = 圖片的寬度 - 裁剪區(qū)域拉伸前的cropOffsertX;
因此此時(shí) cropOffsertX = 拉伸前的裁剪區(qū)域的offsetX(cropChangeX); }
如下圖所示:
if (cropOldW + fw <=0) { // 如果原始裁剪區(qū)域的寬度 + 拉伸的距離小于或等于0的話(huà),說(shuō)明是向左拉伸,并且拉伸的距離正好大于或等于裁剪區(qū)域原始的寬度; }
這邊向左拉伸的距離又可以分為2種情況,第一種是 向左拉伸的距離 小于 (原始裁剪區(qū)域 + 拉伸前的offsetX); 第二種就是向左拉伸的時(shí)候越界了,
那么讓拉伸后的寬度還控制在 offsetX的寬度即可,即不越界;因此如下邏輯判斷:
現(xiàn)在圖片裁剪區(qū)域的寬度(cropW) = (圖片的寬度w - 拉伸前的offsetX + Math.abs(拉伸的總距離 + 裁剪前的原始距離)) <= 圖片的寬度w ? Math.abs(拉伸的總距離 + 裁剪前的原始距離) : 拉伸前的offsetX; 此時(shí)的 cropOffsertX = (圖片的寬度w - 拉伸前的offsetX + Math.abs(拉伸的總距離 + 裁剪前的原始距離)) <= 圖片的寬度w ?拉伸前的offsetX - Math.abs(拉伸的總距離 + 裁剪前的原始距離) : 0; 如下圖所示:
6-2 向上或向下拉伸的基本原理
if (canChangeY) { // 如果Y軸能改變的話(huà),說(shuō)明是 裁剪區(qū)域中上下兩根線(xiàn)或是上下兩個(gè)線(xiàn)上的點(diǎn)了。 if (this.changeCropTypeY === 1) { // 如果Y軸的基點(diǎn)能改變的話(huà),并且等于1,說(shuō)明是裁剪區(qū)域上邊的線(xiàn)或上邊線(xiàn)上的點(diǎn)了。 // 那就有四種可能值,1. 上邊的線(xiàn),2. 上左角的點(diǎn),3. 上中角的點(diǎn)。 4. 上右角的點(diǎn)。 } else if(this.changeCropTypeY === 2) { // 等于2,說(shuō)明是裁剪區(qū)域下邊的線(xiàn)或下邊線(xiàn)上的點(diǎn)了。 // 同理也就有四種可能值,1. 下邊的線(xiàn),2. 下左角的點(diǎn),3. 下中角的點(diǎn)。 4. 下右角的點(diǎn)。 } }
changeCropTypeY === 1 的情況;
假設(shè)裁剪區(qū)域的原始寬度為 cropOldH,裁剪區(qū)域的原始高度為 cropOldY, cropChangeY 保存原始的裁剪區(qū)域相對(duì)于圖片的e.offsetY,
向上或向下拉伸的距離為fh.
如果是向下拉伸的話(huà),又分為2種情況,第一種是向下拉伸它的距離不超過(guò)原始裁剪區(qū)域的高度 cropOldH, 第二種是已經(jīng)超過(guò)它的原始裁剪區(qū)域的高度了。
if (原始裁剪區(qū)域的高度cropOldH - 拉伸的距離fh > 0) { // 說(shuō)明是向上拉伸(fw肯定為負(fù)數(shù))或向下拉伸(fw肯定為正數(shù)),但是向下拉伸的距離不超過(guò)原裁剪區(qū)域的高度 裁剪區(qū)域后的高度cropH 計(jì)算又分為2種情況,第一種是向上拉伸的距離fh小于或等于拉伸前的 e.offsetY, 第二種拉伸距離是大于e.offsetY,也就是向上 拉伸的時(shí)候越界了, 如果越界了,那么拉伸后的高度 = 裁剪之前的原始高度 + e.offsetY(裁剪區(qū)域之前的offsetY);因此: 裁剪區(qū)域后的高度cropH = 圖片的高度 - e.offsetY(裁剪區(qū)域之前的offsetY) - fh <= 圖片的高度 ? 圖片的原始高度cropOldH - 拉伸的距離fh : 裁剪之前的原始高度 + e.offsetY(裁剪區(qū)域之前的offsetY); 拉伸區(qū)域之后的cropOffsertY = 圖片的高度 - e.offsetY(裁剪區(qū)域之前的offsetY) - fh <= 圖片的高度 ? e.offsetY(裁剪區(qū)域之前的offsetY) + fh : 0 }
如下圖所示:
if (原始裁剪區(qū)域的高度cropOldH - 拉伸的距離fh <= 0) { // 說(shuō)明是向下拉伸,且拉伸的距離fh大于或等于原始裁剪區(qū)域的高度cropOldH 同時(shí)一樣也要判斷兩種情況,第一種是向下拉伸后,沒(méi)有超過(guò)圖片的最低端,第二種是超過(guò)了圖片的最低端,也就是越界的情況。 拉伸后裁剪區(qū)域的高度 = 拉伸后的總距離fh + 拉伸前的offsetY <= 圖片的高度h ? 拉伸后的總距離fh - 裁剪區(qū)域原始的高度cropOldH : 圖片的高度H - 拉伸前的offsetY - 裁剪區(qū)域原始的高度 cropOldH; 拉伸區(qū)域之后的cropOffsetY = 拉伸前的offsetY + 裁剪區(qū)域原始的高度cropOldH; }
如下圖所示:
changeCropTypeY === 2 的情況
等于2,說(shuō)明是裁剪區(qū)域下邊的線(xiàn)或下邊線(xiàn)上的點(diǎn)了。
if (原裁剪區(qū)域的高度 + 被拉伸的距離fh > 0) { // 說(shuō)明了有可能是向下拉伸,或向上拉伸,但是向上拉伸的距離小于原裁剪區(qū)域的高度 裁剪區(qū)域后的高度 = 原裁剪區(qū)域的高度 + 被拉伸的距離fh + 原始裁剪區(qū)域的offsetY <= 圖片的高度 ? 原裁剪區(qū)域的高度 + 被拉伸的距離fh : 圖片的高度 - 原始裁剪的offsetY 裁剪后的cropOffsertY = 原始裁剪的offsetY; }
如下圖所示:
if (原裁剪區(qū)域的高度 + 被拉伸的距離fh <= 0) { // 說(shuō)明是向上拉伸,且向上拉伸的距離大于或等于原始裁剪區(qū)域的高度 裁剪區(qū)域后的高度 = 圖片的高度 - 原裁剪區(qū)域的offsetY + Math.abs(fh + 原裁剪區(qū)域的高度) <= 圖片的高度 ? 原裁剪區(qū)域的高度 + 被拉伸的總距離fh : 原裁剪區(qū)域的offsetY; 裁剪后的offsetY = 圖片的高度 - 原裁剪區(qū)域的offsetY + Math.abs(fh + 原裁剪區(qū)域的高度) <= 圖片的高度 ? 原裁剪區(qū)域的offsetY - Math.abs(被拉伸的總距 離fh + 原裁剪區(qū)域的高度) : 0; }
如下圖所示:
6-3: 向左或向右拉伸且是固定比例拉伸,假設(shè)固定比例 3:4, 即 fixedNumber = [3, 4];
向左或向右拉伸,高度會(huì)隨著變化。如下圖所示:
if (canChangeX && fixed) { 比如寬和高比是 3:4 這樣的比例;fixedNumber = [3, 4] 因此 固定比例高度的計(jì)算 裁剪區(qū)域的高度 fixedNumber[1] ------------- = --------------- 裁剪區(qū)域的寬度 fixedNumber[0] 因此: var 裁剪區(qū)域的高度(fixedHeight) = ~~(裁剪區(qū)域的寬度 / fixedNumber[0] * fixedNumber[1]); if (裁剪區(qū)域的高度 + 原裁剪區(qū)域的offsetY > 圖片的高度) { // 說(shuō)明向左拉伸或向右拉伸,導(dǎo)致縱向區(qū)域越界了, 拉伸后的高度 = 圖片的高度 - 原裁剪區(qū)域的offsetY; 拉伸后的寬度 3 ---------- = ---- 拉伸后的高度 4 拉伸后的寬度 = 拉伸后的高度 / fixedNumber[1] * fixedNumber[0]; } else { 拉伸后的高度 = fixedHeight; } }
同樣的道理,如果Y軸上的上下線(xiàn)拉伸的話(huà),寬度會(huì)跟著變化,也是一樣的計(jì)算方式:
if (this.canChangeY && this.fixed) { 比如寬和高比是 3:4 這樣的比例;fixedNumber = [3, 4]; 因此 固定比例寬度的計(jì)算 裁剪區(qū)域的高度 fixedNumber[1] ------------- = --------------- 裁剪區(qū)域的寬度 fixedNumber[0] 裁剪區(qū)域的寬度(fixedWidth) = ~~(裁剪區(qū)域的高度 / fixedNumber[1] * fixedNumber[0]); if (裁剪區(qū)域的寬度 + 原裁剪區(qū)域的offsetX > 圖片的寬度) { // 說(shuō)明向上或向下拉伸,橫向區(qū)域越界了 拉伸后的寬度 = 圖片的寬度 - 原裁剪區(qū)的offsetX; 拉伸后的寬度 3 ---------- = ---- 拉伸后的高度 4 拉伸后的高度 = 拉伸后的寬度 / fixedNumber[0] * fixedNumber[1]; } else { 拉伸后的寬度 = fixedWidth; } }
7. 截圖移動(dòng)操作
首先可以先獲取原裁剪區(qū)域的offsetx,和 offsetY, 該offsetX和offsetY是相對(duì)于瀏覽器的,因此原坐標(biāo)的x軸和Y軸的 e.clientx 和 e.clientY;
當(dāng)鼠標(biāo)移動(dòng)裁剪區(qū)到一個(gè)新坐標(biāo)的時(shí)候,會(huì)有一個(gè)新的 e.clientX 和 e.clientY; 把終點(diǎn)的x軸和Y軸離客戶(hù)端的距離 - 起點(diǎn)的x軸和Y軸的距離,
就等于移動(dòng)了多少的距離了,再加上原裁剪區(qū)相對(duì)于瀏覽器的 offsetX 或 offsetY后,就是最終相對(duì)于瀏覽器的坐標(biāo)了;因此;
fw = 終點(diǎn)的x軸坐標(biāo)(e.clientX) - 起點(diǎn)的x軸坐標(biāo)(e.clientX) + 原裁剪區(qū)相對(duì)于瀏覽器的x軸坐標(biāo)(offsetX);
fh = 終點(diǎn)的y軸坐標(biāo)(e.clientY) - 起點(diǎn)的y軸坐標(biāo)(e.clientY) + 原裁剪區(qū)相對(duì)于瀏覽器的y軸坐標(biāo)(offsetY);
如下圖所示:
if (移動(dòng)后的距離fw小于或等于1的話(huà)) { 移動(dòng)后的cropOffsertX = 1; } else if ((移動(dòng)后的距離 + 裁剪區(qū)域的寬度) > 圖片的寬度的話(huà)) { // 說(shuō)明移動(dòng)的裁剪區(qū)域越界了,那么就讓裁剪區(qū)處于中間的位置 移動(dòng)后的cropOffsertX = 圖片的寬度 - 裁剪區(qū)的寬度 - 1; }
如下圖所示:
else { 移動(dòng)后的cropOffsertX = fw; } 同理 if (移動(dòng)后的距離fh小于或等于1的話(huà)) { 移動(dòng)后的cropOffsertY = 1; } else if ((移動(dòng)后的距離 + 裁剪區(qū)域的高度) > 圖片的高度的話(huà)) { // 說(shuō)明移動(dòng)的裁剪區(qū)域越界了,那么就讓裁剪區(qū)處于中間的位置 移動(dòng)后的cropOffsertY = 圖片的高度 - 裁剪區(qū)的高度 - 1; } else { 移動(dòng)后的cropOffsertY = fh; }
8. 自動(dòng)截圖操作
代碼的基本原理是:看組件是否傳遞了 autoCropWidth 和 autoCropHeight, 如果傳遞了該參數(shù)的寬度和高度的話(huà),那么使用該參數(shù)的值,
如果沒(méi)有傳遞的話(huà),或者說(shuō)該寬度和高度的值都為0的話(huà),那么截取的寬度和高度就是圖片的寬度和高度的80%;如果傳遞的寬度w和高度h大于圖片的
本身的寬度或高度的話(huà),那么寬度或高度的值就是圖片的本身的寬度和高度的值。
如果傳遞了固定比例的話(huà),那么高度的計(jì)算是根據(jù)寬度的比例來(lái)計(jì)算出來(lái)的。計(jì)算方式還是之前一樣的:如下:
w fixedNumber[0] ------------- = --------------- h fixedNumber[1]
因此 h = w / this.fixedNumber[0] * this.fixedNumber[1]
如果高度大于圖片的高度的話(huà),那么高度就是等于圖片的高度,然后根據(jù)現(xiàn)在的高度重新計(jì)算寬度;
代碼如下:
// 如果比例之后 高度大于h if (h > this.h) { h = this.h w = h / this.fixedNumber[1] * this.fixedNumber[0] }
自動(dòng)截圖的主要代碼如下:
var w = this.autoCropWidth var h = this.autoCropHeight if (w === 0 || h === 0) { w = this.w * 0.8 h = this.h * 0.8 } w = w > this.w ? this.w : w h = h > this.h ? this.h : h if (this.fixed) { h = w / this.fixedNumber[0] * this.fixedNumber[1] } // 如果比例之后 高度大于h if (h > this.h) { h = this.h w = h / this.fixedNumber[1] * this.fixedNumber[0] }
總結(jié)
以上所述是小編給大家介紹的Vue-cropper 圖片裁剪的基本原理及思路講解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- 前端vue-cropperjs實(shí)現(xiàn)圖片裁剪方案
- Vue使用Vue-cropper實(shí)現(xiàn)圖片裁剪
- vue圖片裁剪插件vue-cropper使用方法詳解
- 基于cropper.js封裝vue實(shí)現(xiàn)在線(xiàn)圖片裁剪組件功能
- vue-cli結(jié)合Element-ui基于cropper.js封裝vue實(shí)現(xiàn)圖片裁剪組件功能
- cropper js基于vue的圖片裁剪上傳功能的實(shí)現(xiàn)代碼
- vue移動(dòng)端裁剪圖片結(jié)合插件Cropper的使用實(shí)例代碼
- 在Vue3項(xiàng)目中使用VueCropper裁剪組件實(shí)現(xiàn)裁剪及預(yù)覽效果
相關(guān)文章
Vue中Keep-Alive緩存組件使用語(yǔ)法及原理深度解析
keep-alive是vue中的內(nèi)置組件,能在組件切換過(guò)程中將狀態(tài)保留在內(nèi)存中,防止重復(fù)渲染DOM,這篇文章主要介紹了Vue中Keep-Alive緩存組件使用語(yǔ)法及原理,需要的朋友可以參考下2024-07-07基于ElementUI實(shí)現(xiàn)v-tooltip指令的示例代碼
文本溢出隱藏并使用tooltip 提示的需求,相信在平時(shí)的開(kāi)發(fā)中會(huì)經(jīng)常遇到,常規(guī)做法一般是使用 elementui 的 el-tooltip 組件,在每次組件更新的時(shí)候去獲取元素的寬度/高度判斷是否被隱藏,本文給大家介紹了基于ElementUI實(shí)現(xiàn)v-tooltip指令,需要的朋友可以參考下2024-09-09詳解vue-router的導(dǎo)航鉤子(導(dǎo)航守衛(wèi))
這篇文章主要介紹了詳解vue-router的導(dǎo)航鉤子(導(dǎo)航守衛(wèi)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11vue的v-if里實(shí)現(xiàn)調(diào)用函數(shù)
這篇文章主要介紹了vue的v-if里實(shí)現(xiàn)調(diào)用函數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07el-form的model、prop屬性和表單校驗(yàn)等使用
本文主要介紹了el-form的model、prop屬性和表單校驗(yàn)等使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Vue前端項(xiàng)目部署IIS的實(shí)現(xiàn)
這篇文章主要介紹了Vue前端項(xiàng)目部署IIS的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01vue+iview+less+echarts實(shí)戰(zhàn)項(xiàng)目總結(jié)
本篇文章是作者通過(guò)學(xué)習(xí)vue+iview+less+echarts制作一個(gè)小系統(tǒng)后,做的心得以及遇到的坑的總結(jié),值得大家學(xué)習(xí)參考。2018-02-02