• 自制一个H5图片拖拽、裁剪插件(原生JS)


    前言

    如今的H5运营活动中,有很多都是让用户拍照或者上传图片,然后对照片加滤镜、加贴纸、评颜值之类的。尤其是一些拍照软件公司的运营活动几乎全部都是这样的。

    博主也做过不少,为了省事就封装了一个简单的图片拖拽、裁剪的插件。其实网上也有很多类似的插件,只不过有的功能冗余体积大,有的甚至还依赖jquery。索性自己搞一个轻量的,只是不支持缩放功能。

    DEMO(手机上看效果比较好,PC上没有兼容处理),原码

    实现

    这里简略说下实现过程,只截取部分代码片段,有兴趣的可以看下原码,反正也很简单。

    图片上传

    这个DEMO里使用的上传方式是HTML5的 File Input,但是很多运营活动需要调用微信的上传&拍照接口,由于以前踩过坑这里就啰嗦两句,帮助新人绕开。

    · 在 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 对象移除。具体的细节可以参考原码,整体比较简单。

    -转载

  • 相关阅读:
    FineReport自学习题第四题——图表
    SQL如何查询连续数字并且统计连续个数
    Arm Cortex-M3 MCU性能
    北汽蓝谷极狐阿尔法S与T
    长鑫存储DDR产品
    华虹宏力芯片制造主流工艺技术
    传统编译器与神经网络编译器
    Apple苹果公司组织架构
    GPU与CPU交互技术
    CMOS图像传感器与DDI显示芯片
  • 原文地址:https://www.cnblogs.com/alinaxia/p/6401116.html
Copyright © 2020-2023  润新知