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 中的处理方法便可。