前段時間做了個跟裁剪相關的活動《用H5中的Canvas等技術制作海報》,這次公司要做個與奧運相關的活動,掃車牌贏獎。
於是我就在上一個活動的基礎上,將代碼重新封裝一下,並且將計算方式寫的更通用。下圖是活動中裁剪的頁面:
先來看看兩個活動的不同:
1、原先的活動每次旋轉只能90°,而此次活動可以任意角度旋轉。
2、原先的活動每次旋轉就會生成一段Base64數據,導致頁面卡頓嚴重,而此次只有在裁剪的時候才生成圖片。
以上兩點是最大的不同,其它方面基本一致,如果碰到不明白的可以參考一下《海報制作》
Github的插件項目中,index.html頁面是一個示例demo。
一、裁剪原理
1)計算坐標
在上一篇海報制作的文章中,提到了裁剪時候各個位置的計算。這次使用的計算方式與上次一樣。
最終也是在分別獲取裁剪框與圖片的x、y和寬高。
只是此次是任意角度的旋轉,所以在裁剪的時候要使用更通用的計算方式。
2)生成旋轉圖片
我在最終裁剪的時候,會先生成一張旋轉后的圖片,然后再在這張圖片中裁剪指定區域。
在上圖中選中的透明藍色部分就是一張旋轉后的圖片,這里只能看到部分,其實完整的應該是會比原圖的寬大很多。
而通過計算后的裁剪框與圖片的位置如下:
image的x和y坐標大概就是上圖中紅點的位置,如果要裁剪就要生成這張旋轉后的圖片。
細的藍色線條描繪了旋轉后的圖片樣子,這里只展示到了部分。接下來就是如何計算得到這張圖片。
二、三角函數
要生成上面那張旋轉圖片,需要通過三角函數計算出寬高,以及在Canvas上畫圖的時候需要偏移的值。
通過手工計算,得出旋轉分為四種情況90°以內、180°以內、270°以內和360°以內。
上圖是我手工計算的90°以內的情況,可以計算出x1、x2、y1、y2,旋轉角度是30°。
知道了這四個值就能計算出新圖的寬和高,還能得出需要平移的坐標值,像上圖就是(x2,0)。
插件中函數“radian”,“sin”,“cos”,“caculate1”,“caculate2”,“rotateCanvas”都是在做三角函數相關計算。
其他三個情況以此類推。
最終圖片生成是在方法“filterImage”中做的,下面是部分代碼。
順便說下,最后canvas生成了jpeg圖片,並且質量是0.5,這是為了減小圖片的大小,使得在性能差的手機上面也能做操作。
三、旋轉
當在操作圖片的時候,我通過手勢庫touch.js綁定的事件,獲取到了角度,然后再將這個角度設置到CSS屬性“rotate”中,使得圖片旋轉了起來。
平移和縮放分別用到了“translate3d”和“scale3d”,用3d屬性是為了增強性能。
在插件的“initTouch”方法中配置了手勢事件。插件的私有屬性“param”緩存了平移、縮放和角度的值。
veCropProtytype.initTouch = function() { var currScale, _this = this, Touch = this.opts.Touch, frame = this.opts.frame; Touch.on(frame, 'rotate', function (ev) { var totalAngle = _this.param.deg + ev.rotation; if(ev.fingerStatus === 'end'){ _this.param.deg = _this.param.deg + ev.rotation; } _this.formatTransform(_this.param.offsetX, _this.param.offsetY, _this.param.scale, totalAngle); }); //...... };
Github上的地址:
https://github.com/pwstrick/veCrop