SimpleCrop
目前是全網惟一
支持裁剪圖片任意角度旋轉、交互體驗媲美原生客戶端
的全平臺
圖片裁剪組件。css
項目地址:github.com/newbieYoung…。html
和目前流行的圖片裁剪組件相比,其優點在於如下幾點:git
左側是 IOS 系統相冊中原生的圖片裁剪功能,右側爲 SimpleCrop 移動端示例。github
能夠掃描二維碼體驗:web
或者訪問如下連接:canvas
newbieyoung.github.io/Simple-Crop…小程序
連接以下:微信小程序
newbieyoung.github.io/Simple-Crop…瀏覽器
要實現任意角度旋轉
、雙指中心縮放
、邊界判斷
、自動吸附
等功能,關鍵點以下:bash
在裁剪圖片場景中,存在兩個座標系,其一是裁剪圖片所表明的實際尺寸座標系,其二是裁剪框顯示到屏幕上所表明的屏幕座標系;後續進行 transform 變換計算和位置判斷時,爲了計算方便,須要把裁剪圖片的尺寸以及位置從實際座標系轉換爲屏幕座標系。另外當對裁剪圖片進行 transform 變換時,變換基準點默認爲其中心點,對應 CSS 的 transform-origin 爲 50% 50%。
首先須要實時獲取裁剪圖片進行 CSS Transform 變換後的新座標,只有在實時獲取變換後的新座標的前提下才能結合裁剪框座標進行越界、吸附等判斷;
在計算 CSS Transform 變換後的新座標時須要注意選取的屏幕座標系和 CSS Transform 座標系的差異,好比示例中以黑色邊框中心爲座標原點,水平向左爲 X 軸正方向,垂直向上爲 Y 軸正方向;可是 CSS Transform 的座標系垂直向下爲 Y 軸正方向和上述規定的座標系 Y 軸正方向是相反的,所以在獲取 CSS Transform 變換矩陣以後求實時座標時還須要進行鏡像變換。
詳細計算過程能夠查看 CSS3 2D Transform Matrix。
裁剪圖片任意角度旋轉時須要進行適當的放大才能保證裁剪框不超出,所以就須要先計算裁剪框哪些點超出,而後根據超出的點計算恰好包含的放大倍數。
當兩個矩形位置關係任意變換時計算相互之間有哪些點超出有兩種方案:
其一:
圖中左側紅色矩形表明裁剪圖片,黑色矩形表明裁剪框,如圖所示裁剪框頂點 A 超出了裁剪圖片。
鏈接矩形四個頂點和判斷點,而後計算四條連線之間的夾角,若是夾角之和小於 360 度,那麼該判斷點在矩形外;反之若是夾角之和等於 360 度,那麼該判斷點在矩形內。
a1 + a2 + a3 + a4 < 360
b1 + b2 + b3 + b4 = 360
複製代碼
其二:
圖中黑色矩形表示裁剪圖片,點 A 表示裁剪框中超出裁剪圖片的某個頂點。
鏈接矩形中心點和判斷點,而後計算中心點和判斷點向量在矩形邊框向量上的投影長度(L一、L2),只要兩個投影長度中有任意投影長度大於其投影邊框長度(H一、H2)的一半即說明該點在矩形外。
另外還能夠根據投影長度和其投影邊框長度的比例計算出矩形剛好包含該點的放大係數,也就是示例圖中的 S 變量。
最後旋轉圖片時除了要進行適當的放大,保證裁剪框不超出之外,還能夠在裁剪圖片中心點沒有變更時進行適當的縮小,去掉多餘間隙,進一步提高交互體驗。
縮小系數的計算原理和放大係數的計算原理相似,均是鏈接判斷點和中心點,而後根據邊框投影長度計算。
大矩形爲裁剪圖片,小矩形表示裁剪框,O 表示裁剪圖片中心點。
因爲默認裁剪圖片的變換基準點爲其中心點,這麼處理雖然計算方便,可是會對雙指縮放形成必定的困難;由於雙指操做時雙指中心並不必定是裁剪圖片中心。
解決方案須要先求出兩個不一樣基準點的位移差,而後在進行縮放變換以後再進行位移變換。
在旋轉裁剪圖片時能夠對其進行適當得放大和縮小從而保證裁剪框不會超出裁剪圖片;可是在雙指操做縮放裁剪圖片卻不能這麼作,由於適配縮放會和用戶的操做縮放衝突,所以須要採用移動裁剪圖片的方式保證裁剪框不超出裁剪圖片。
當裁剪圖片進行位移變換以後能夠包含裁剪框,就只須要計算位移向量;
紅色矩形爲裁剪圖片,黑色矩形爲裁剪框。
可是還有一種狀況即裁剪圖片進行位移變換以後不能包含裁剪框,以下:
紅色實線矩形爲裁剪圖片,黑色矩形爲裁剪框,紅色虛線矩形爲進行放大以後剛好包含裁剪框的裁剪圖片。
此時說明用戶的操做縮放超出了組件的合法限制範圍,能夠加入適配縮放了;這時候就須要先計算裁剪圖片剛好包含裁剪框的放大係數,而後再進行位移變換。
在整個實現過程當中還涉及到大量 Canvas API 操做,須要注意如下幾點;
使用微信小程序 type 2d Canvas API 時遇到了一些坑。好比:在 Android 中 Canvas 不支持 transform style,而在 IOS 中 Canvas 設置 width 和 height 屬性以前須要先設置其 style 的 width 和 height 不然不會生效;
Canvas 元素的尺寸在瀏覽器中是有最大限制的,超出後瀏覽器會報警告canvas area exceeds the maximum limit 並且繪製的結果爲空白;
使用 Image 標籤展現圖片時瀏覽器會忽視圖片的方向角數據,可是使用 Canvas API 繪製時又會考慮方向角;在處理圖片時須要注意不一樣標籤間的差別。建議的方案是使用 Exif.js 獲取圖片元數據,而後借鑑 JavaScript-Load-Image 中的處理方法便可。