自制一個H5圖片拖拽、裁剪插件(原生JS)

前言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 對象移除。具體的細節能夠參考原碼,總體比較簡單。

 

感謝你的瀏覽,但願能有所幫助

相關文章
相關標籤/搜索