自制一个H5图片拖拽、裁剪插件(原生JS)
前言
如今的H5运营活动中,有很多都是让用户拍照或者上传图片,然后对照片加滤镜、加贴纸、评颜值之类的。尤其是一些拍照软件公司的运营活动几乎全部都是这样的。
博主也做过不少,为了省事就封装了一个简单的图片拖拽、裁剪的插件。其实网上也有很多类似的插件,只不过有的功能冗余体积大,有的甚至还依赖jquery。索性自己搞一个轻量的,只是不支持缩放功能。
实现
这里简略说下实现过程,只截取部分代码片段,有兴趣的可以看下原码,反正也很简单。
图片上传
这个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 对象移除。具体的细节可以参考原码,整体比较简单。
感谢你的浏览,希望能有所帮助
自制一个H5图片拖拽、裁剪插件(原生JS)的更多相关文章
- HTML5图片拖拽预览原理及实现
一.前言 这两天恰好有一位同事问我怎样做一个图片预览功能.作为现代人的我们首先想到的当然是HTML5啦,其实HTML5做图片预览已经是一个老生常谈的问题了.我在这里就简单说说其中相关的一些东西,当然会 ...
- 11个好用的jQuery拖拽拖放插件
这次我们整理一些拖拽播放类型的jQuery插件,这些可能不是很常用,但偶尔会有网站设计项目用到,特别是后台相关的开发项目,这个拖放排序功能一般都会有,所以适合大家收藏起来,方便日后使用.接下来一起看盾 ...
- Vue富文本编辑器(图片拖拽缩放)
富文本编辑器(图片拖拽缩放) 需求: 根据业务要求,需要能够上传图片,且上传的图片能在移动端中占满屏幕宽度,故需要能等比缩放上传的图片,还需要能拖拽.缩放.改变图片大小.尝试多个第三方富文本编辑器,很 ...
- canvas 图片拖拽旋转之二——canvas状态保存(save和restore)
引言 在上一篇日志“canvas 图片拖拽旋转之一”中,对坐标转换有了比较深入的了解,但是仅仅利用坐标转换实现的拖拽旋转,会改变canvas坐标系的状态,从而影响画布上其他元素的绘制.因此,这个时候需 ...
- canvas 图片拖拽旋转之一——坐标转换translate
引言 对canvas中绘制的图片进行旋转操作,需要使用ctx.translate变换坐标系,将图片旋转的基点设为坐标系的原点,然后ctx.rotate旋转. 这个时候,因为canvas坐标系发生了旋转 ...
- HTML5多图片拖拽上传带进度条
前言 昨天利用css2的clip属性实现了网页进度条觉得还不错,但是很多情况下,我们在那些时候用进度条呢,一般网页加载的时候如果有需要可以用,那么问题就来了,怎么才算整个加载完毕呢,是页面主要模块加载 ...
- Android高级控件(六)——自定义ListView高仿一个QQ可拖拽列表的实现
Android高级控件(六)--自定义ListView高仿一个QQ可拖拽列表的实现 我们做一些好友列表或者商品列表的时候,居多的需求可能就是需要列表拖拽了,而我们选择了ListView,也是因为使用L ...
- Android 仿微信朋友圈发表图片拖拽和删除功能
朋友圈实现原理 我们使用 Android Device Monitor 来分析朋友圈发布图片的界面实现原理.如果需要分析其他应用的界面实现也是采用这种方法哦. 打开 Android Device Mo ...
- vue在移动端使用alloyfinger手势库操作图片拖拽、缩放
最近开发一个活动需要在手机上给上传的头像加上边框.装饰,需要拖拽.手势缩放边框下的头像图片,因为是vue项目,开始尝试了vue-drag-resize这个组件,对图片拖拽支持很完美,但是无法手势缩放, ...
随机推荐
- EOFException异常详解
最近线上的系统被检测出有错误日志,领导让我检查下问题,我就顺便了解了下这个异常. 了解一个类,当然是先去看他的API,EOFException的API如下: 通过这个API,我们可以得出以下信息: 这 ...
- __细看InnoDB数据落盘 图解 MYSQL
http://hatemysql.com/?p=503 1. 概述 前面很多大侠都分享过MySQL的InnoDB存储引擎将数据刷新的各种情况.我们这篇文章从InnoDB往下,看看数据从InnoDB的 ...
- MySQl新特性 GTID
GTID简介 概念 全局事务标识符(GTID)是创建的唯一标识符,并与在源(主)服务器上提交的每个事务相关联.此标识符不但是唯一的,而且在给定复制设置中的所有服务器上都是唯一的.所有交易和所有GTID ...
- Windows Server 2012 R2 创建AD域
前言 我们按照下图来创建第一个林中的第一个域.创建方法为先安装一台Windows服务器,然后将其升级为域控制器.然后创建第二台域控制器,一台成员服务器与一台加入域的Win8计算机. 环境 网络 ...
- UNIX高级环境编程(15)进程和内存分配 < 故宫角楼 >
故宫角楼是很多摄影爱好者常去的地方,夕阳余辉下的故宫角楼平静而安详. 首先,了解一下进程的基本概念,进程在内存中布局和内容. 此外,还需要知道运行时是如何为动态数据结构(如链表和二叉树)分配额外内 ...
- rename 批量修改文件名简单用法
有的时候我们需要批量创建文件做测试,为了做区分,一般只要稍稍动动文件名即可,MV命令既可以移动文件,也是可以修改文件名的,但批量修改文件名MV做不到,此时,我们可以用rename命令批量修改是蛮不错的 ...
- oracl数据库中的substr()函数的用法
substr:字符串截取. 1.substr:(字符串 | 列 ,开始点):从开始一直截取到结尾. select substr(zym,2) from bqh4 2.substr:(字符串 | 列 , ...
- Linux 配置 hosts
1. hosts 是什么 维基百科对 hosts 的介绍如下: hosts文件(域名解析文件)是一个用于储存计算机网络中各节点信息的计算机文件. 这个文件负责将主机名称映射到相应的IP地址. host ...
- PHPStorm 中配置 XDebug
1.下载 Xdebug ps : php版本和xdebug版本一定要相对应 如果不知道下载哪个版本,将phpinfo网页的源代码拷贝到https://xdebug.org/wizard.php,然后按 ...
- 关于Java集合类库中的几种常用队列
Java中几种常用的队列 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞 ...