前言html
現在的H5運營活動中,有不少都是讓用戶拍照或者上傳圖片,而後對照片加濾鏡、加貼紙、評顏值之類的。尤爲是一些拍照軟件公司的運營活動幾乎所有都是這樣的。jquery
博主也作過很多,爲了省事就封裝了一個簡單的圖片拖拽、裁剪的插件。其實網上也有不少相似的插件,只不過有的功能冗餘體積大,有的甚至還依賴jquery。索性本身搞一個輕量的,只是不支持縮放功能。git
DEMO(手機上看效果比較好,PC上沒有兼容處理),原碼github
實現web
這裏簡略說下實現過程,只截取部分代碼片斷,有興趣的能夠看下原碼,反正也很簡單。算法
圖片上傳canvas
這個DEMO裏使用的上傳方式是HTML5的 File Input,可是不少運營活動須要調用微信的上傳&拍照接口,因爲之前踩過坑這裏就囉嗦兩句,幫助新人繞開。api
· 在 wx.config 中的 jsApiList 屬性中添加 chooseImage 和 uploadImage API。緩存
· 調用 chooseImage API,得到 localId。服務器
wx.chooseImage({ count: 1, // 默認9 sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success: (res) => { var localIds = res.localIds[0]; console.log(localIds); } });
須要注意的是這裏的 localId 能夠經過 img 標籤的 src 屬性進行展現,可是沒法傳給服務器接口或者經過 canvas 裁剪,因此還須要上傳一步。
· 調用 uploadImage API,將以前獲得的 localId 傳入,得到 serverId。
wx.uploadImage({ localId: localIds, isShowProgressTips: 1, success: (res) => { var serverId = res.serverId; console.log(serverId); } });
有了 serverId 其實就能夠獲得保存在微信服務器上的圖片了,只是博主以前還去多餘的下載一道。
將一開始微信認證時得到的 accessToken 與 serverId 拼接到下面的連接便可直接引用
const imgUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + accessToken + "&media_id=" + serverId;
接下來就能夠建立 image 對象,設置 src 屬性,完成拖拽裁切等操做。
初始化
首先要對圖片的尺寸進行調整:
· 若圖片寬高比比容器的大,即圖片比容器「扁」,就讓圖片的高度與容器保持一致,寬度自動適應保持原圖比例不變
· 若圖片寬高比比容器的小,即圖片比容器「瘦」,就讓圖片的寬度與容器保持一致,高度自動適應保持原圖比例不變
爲了便於理解,咱們假設容器高寬爲1:1,爲下圖中紅色線框區域:
代碼片斷
var img = new Image(), _this = this; img.src = imgUrl; img.style.webkitUserSelect = 'none'; img.onload = function() { var imgWidth = img.width, imgHeight = img.height, imgRate = imgWidth / imgHeight, conRate = conWidth / conHeight; if (imgRate > conRate) { //寬型 var imgCurrentHeight = _this.opts.conHeight, imgCurrentWidth = imgCurrentHeight * imgRate, maxOffset = conWidth - imgCurrentWidth; img.setAttribute('width', 'auto'); img.setAttribute('height', _this.opts.conHeight); //...... } else { //高型 var imgCurrentWidth = _this.opts.conWidth, imgCurrentHeight = imgCurrentWidth / imgRate, maxOffset = conHeight - imgCurrentHeight; img.setAttribute('width', '100%'); //...... } }
上述代碼就完成了基本的圖片大小調整,其中 conWidth, conHeight 是插件接收的容器高與寬,maxOffset 是圖片容許拖拽的最大偏移量。
拖拽
這裏我使用了一個比較輕量的手勢庫——hammer.js,經過手勢的位移改變圖片的 translate 屬性值。
這裏只截取橫向拖拽的代碼片斷,縱向相似
hammer.on('pan', function(e) { var current = img.style.transform ? img.style.transform.split('(')[1].split('px')[0] : 0, move = Number(current) + (e.deltaX * (_this.opts.speed/10)); if (move >= 0 || move <= maxOffset) { return; } img.style.transform = 'translateX('+move+'px)'; _this.cutData.moveX = Math.abs(move); _this.cutData.moveY = 0; });
opts.speed 值爲插件初始化時設置的拖動速度,這裏速度值算法比較簡單,有興趣的朋友可優化使其更平滑些。cutData 用於緩存拖動的位置,用於以後的裁剪。
裁剪
這裏使用了 canvas 對圖片進行裁剪返回 base64碼,能夠將 base64碼直接展現或者經過 POST 接口傳到服務器處理(GET請求長度會超)
cut: function() { var canvas = document.createElement('canvas'), img = document.querySelector('#cutImgObj'), data = this.cutData, cutWidth = this.opts.conWidth / data.scaleRate, cutHeight = this.opts.conHeight / data.scaleRate; canvas.width = cutWidth; canvas.height = cutHeight; canvas.getContext('2d').drawImage(img, data.moveX/data.scaleRate, data.moveY/data.scaleRate, cutWidth, cutHeight, 0, 0, cutWidth, cutHeight); return canvas.toDataURL('image/png'); },
這裏要說明下,因爲圖片進行了縮放,因此須要將畫布調整到原圖的尺寸,同時記錄的拖動位置也須要除以縮放比例。
調用
· 初始化
var cutter = new Cutter(picAreaDom, { imgUrl: url, //圖片連接 conWidth: containerDom.offsetWidth, //容器寬度 conHeight: containerDom.offsetWidth * 1.2, //容器高度 speed: 2, //拖動速度 callback: function() { //doSomething... } });
這裏有個地方要說明下,雖然 Cutter 中的 conWidth,conHeight 屬性默認爲 picAreaDom 的寬高,但若是 picAreaDom 的父級元素爲 display:none,那麼就獲取不到 picAreaDom 尺寸(DEMO中單頁應用機制致使的),這時候就須要顯式傳入裁剪區域的寬高。
callback 爲初始化完成時的回調函數,保存實例化對象 cutter,用於以後的裁剪。
· 裁剪
var result = cutter.cut();
result 值即爲裁剪後的 base64碼。
最後一個小提示,若是須要從新上傳圖片裁剪,記得將容器中的 img 對象移除。具體的細節能夠參考原碼,總體比較簡單。
感謝你的瀏覽,但願能有所幫助