前面曾经写过一篇《H5图片裁剪升级版》,但里面需要借助第三方手势库,这次就不需要使用手势库,全部封装在代码中。

下图是裁剪的展示,下面就做了拖放和裁剪,没有做缩放,在插件中需要用到大量的计算。veImage的源码可以在此处浏览

一、原理

1)拖动缩放裁剪都是借助Canvas实现的。Canvas的基础概念可以参考《让自己也能使用Canvas》。

2)拖动是通过设置Canvas画布左上角的起点实现的。使用CanvasRenderingContext2D.translate方法。

3)缩放是通过设置目标画布上绘制图像的宽度和高度实现的。使用CanvasRenderingContext2D.drawImage方法。

4)裁剪是通过计算比例后(效果图中的画布尺寸与实际网页中的画布尺寸不符),在原画布上面截取计算后的尺寸,画到一张新画布中,新画布的宽高就是需要截取的宽高。

5)拖动缩放是需要计算两个坐标的差值,而这两个坐标是通过e.touches获取到,这个参数可以参考《触屏touch事件记录》。

6)将画布的起始点,设置在画布的中心,也就是宽高的一半。这样设置后,缩放的效果看上去就是向四周缩放。否则效果是固定在图片左上角,然后缩放,如下图所示。

 

二、参数

参数目前就3个。

1)Canvas:画布,可以通过DOM获取到。

2)Image:图片,Image对象,这里先做的简单点,不是传地址。

3)relativeWidth:相对宽度,裁剪的时候可计算比例。

HTML代码如下

<canvas id="captureCanvas2" class="car-img car-canvas"></canvas>

JavaScript代码如下

var imgEdit2;
var img = new Image();
img.src = 'img/car-demo2.jpg';
img.onload = function() {
imgEdit2 = new veImage({canvas:document.getElementById('captureCanvas2'), image:this});
};

三、事件绑定

拖动、缩放涉及的事件是touchstarttouchmovetouchend

给Canvas画布添加上述事件,模拟出手势效果。

事件绑定用到了“handleEvent”方式绑定。前面的《Slider图片滑动插件》也是用相同的方式绑定。

/**
* 绑定事件
*/
veImagePrototype._bind = function() {
this.canvas.addEventListener(events.start, this);
this.canvas.addEventListener(events.move, this);
this.canvas.addEventListener(events.end, this);
};
/**
* 高级的绑定方法
*/
veImagePrototype.handleEvent = function(e) {
switch (e.type) {
case events.start:
this.startEvt(e);
break;
case events.move:
this.moveEvt(e);
break;
case events.end:
this.endEvt(e);
break;
}
};

四、拖动与缩放

1)touchstart

1. 在touchstart事件中记录开始的坐标

2. 通过手指的数量,设置当前的模式,简单处理,1根手指是拖动,2根手指是缩放。

this.start = _finger(e.touches);//记录开始的坐标
this._mode(e.touches);//模式初始化

2)touchmove

1. 记录移动中的坐标。

2. 当模式是1的时候,才做拖动。

3. 原先是通过手指数量来判断,拖动还是缩放,不过后面发现缩放后,移除手指的时候,会出现一个手指还停留在页面上,导致位移一段距离。如下图所示:

 

e.preventDefault(); //禁止滚动

var fingers = _finger(e.touches); //记录移动中的坐标
//不能仅仅通过手指数量来判断 因为当缩放后,移除手指的时候,会出现一个手指还停留在页面上,导致位移
if (this.mode == 1) { //位移
this._translate(fingers);
} else if (this.mode == 2) { //缩放
this._zoom(fingers);
}
//将start的坐标复为移动中的坐标 时时计算偏移值,不然会变得非常大,图片在移动中会飞出画面
this.start = fingers;

3)移动计算

1. 最普通的计算方式,移动中的坐标点减去刚开始触屏的坐标点

2. 向左或上移动,就是负数。

//计算手指的位移
this._draw(
fingers[0].x - this.start[0].x,
fingers[0].y - this.start[0].y
);

4)缩放计算

1. 先计算上一次手指两个X轴和Y轴之间的距离。

2. 再计算当前的手指两个X轴和Y轴之间的距离。

3. 都取绝对值,缩放率分母是上一次手指,分子是当前手指两个X轴和Y轴之间的距离。

//上一次手指两个X轴和Y轴之间的距离
var lastOffset = {
x: Math.abs(this.start[0].x - this.start[1].x),
y: Math.abs(this.start[0].y - this.start[1].y)
};
if (lastOffset.x == 0 || lastOffset.y == 0) { //防止分母是0
return;
}
//缩放不需要坐标轴偏移 但计算缩放值 需要偏移值
//缩放率分母是上一次手指,分子是当前手指两个X轴和Y轴之间的距离
this._draw(
0, 0,
Math.abs(fingers[0].x - fingers[1].x) / lastOffset.x,
Math.abs(fingers[0].y - fingers[1].y) / lastOffset.y
);

五、画图

1)清空画并保存状态

1. 如果不清空画布,那么刚刚拖动的图片还会在画布上,形成了拖影。

2. 保存状态(CanvasRenderingContext2D.save)是为了下面能够还原到清空的画布。

//清空画布 擦除之前绘制的所有内容 不清空的话会显示各个步骤的画布
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.save(); //保存状态

2)拖动消息

拖动是由translate实现的,先计算原点和偏移值的和,再设置画布的原点。

this.origin.x += dx || 0; //计算X轴坐标
this.origin.y += dy || 0; //计算Y轴坐标
this.context.translate(this.origin.x, this.origin.y); //位移

3)缩放效果

缩放是通过改变目标画布的宽高实现的。

zoomWidth = zoomWidth || 1;
zoomHeight = zoomHeight || 1;
var zoom = zoomWidth > zoomHeight ? zoomWidth : zoomHeight; //统一按一个比例做缩放
this.dWidth *= zoom; //宽度缩放
this.dHeight *= zoom; //高度缩放

4)画图

drawImage实现。语法如下:

1. sx, sy, sWidth, sHeight分别是图片的坐标点和宽高。

2. dx, dy, dWidth, dHeight分别是画布缩放后的中心点和缩放后的宽高。

3. 由于原点是在画布的中心点,所以要画到合适的位置,dx, dy就需要用负数坐标点。

this.context.drawImage(
this.image, 0, 0, this.image.width, this.image.height,
-this.dWidth / 2, -this.dHeight / 2, this.dWidth, this.dHeight
); //目标画布的中心点

5)还原状态

如果不还原(restore),就会像下图那样,上一张图还在画布中,也不能拖动或缩放了。

由于前面translate设置了原点,所以下一次画的时候会从这个原点开始。

将原点设置的小一些,就会像下图那样,出现谍影,上图其实也是谍影,只是已经超出画布了,所以看不到。

this.origin = {
x: 30,
y: 30
};

六、裁剪

1)新建一张画布

裁剪后的图片画到这张新画布中。

var canvas = document.createElement("canvas"),
context = canvas.getContext("2d");

2)计算比例

例如效果图上画布的宽是750,那么裁剪的尺寸是相对于750来说的,而实际画布的宽度可能是360,那么这个时候就要做比例计算了。

rate = this.canvas.width / this.opts.relativeWidth;

3)计算尺寸

在获取到比例后,计算真实画布中的坐标和尺寸。

x *= rate;
y *= rate;
canvas.width = w * rate;
canvas.height = h * rate;
context.drawImage(
this.canvas, x, y, canvas.width, canvas.height,
0, 0, canvas.width, canvas.height
);

移动端 H5图片裁剪插件,内置简单手势操作的更多相关文章

  1. 开源JS图片裁剪插件

    开源JS图片裁剪插件 一.总结 一句话总结: 要用点赞最高的插件,这样适用性最好,效果最好,出问题的概率也最低,这里电脑端和手机端都可以用的建议用 cropper.js 二.5款好用的开源JS图片裁剪 ...

  2. Cropper – 简单的 jQuery 图片裁剪插件

    Cropper 是一个简单的 jQuery 图像裁剪插件.它支持选项,方法,事件,触摸(移动),缩放,旋转.输出的裁剪数据基于原始图像大小,这样你就可以用它们来直接裁剪图像. 如果你尝试裁剪跨域图像, ...

  3. Croppic – 免费开源的 jQuery 图片裁剪插件

    Croppic 这款开源的 jQuery 图片裁剪插件能够满足网站开发人员各种不同的使用需要.只需要简单的上传图片,就可以实现你想要的图像缩放和裁剪功能.因为使用了 HTML5 FormData  对 ...

  4. 5 款最新的 jQuery 图片裁剪插件

    这篇文章主要介绍最新的 5 款 jQuery 图片裁剪插件,可以帮助你轻松的实现你网站需要的图像裁剪功能. Cropit Cropit 是一个 jQuery 插件,支持图像裁剪和缩放功能.Cropit ...

  5. jQuery 图片裁剪插件 Jcrop

    Jcrop是一个jQuery图片裁剪插件,它能为你的WEB应用程序快速简单地提供图片裁剪的功能.特点如下: 对所有图片均unobtrusively(无侵入的,保持DOM简洁) 支持宽高比例锁定 支持 ...

  6. 基于jQuery功能非常强大的图片裁剪插件

    今天我们要来介绍一款基于jQuery功能非常强大的图片裁剪插件,这款jQuery图片裁剪插件可以选择裁剪框的尺寸比例,可以设置高宽尺寸,同时可以设置图片翻转角度,当然也支持图片的缩放,裁剪框也可以用鼠 ...

  7. TODO:Laravel 内置简单登录

    TODO:Laravel 内置简单登录 1. 激活Laravel的Auth系统Laravel 利用 PHP 的新特性 trait 内置了非常完善好用的简单用户登录注册功能,适合一些不需要复杂用户权限管 ...

  8. javascript:面向对象和常见内置对象及操作

    本文内容: 面向对象 常见内置对象及操作 首发日期:2018-05-11 面向对象: JavaScript 是面向对象的编程语言 (OOP).OOP 语言使我们有能力定义自己的对象和变量类型. 对象是 ...

  9. H5图片裁剪升级版

    前段时间做了个跟裁剪相关的活动<用H5中的Canvas等技术制作海报>,这次公司要做个与奥运相关的活动,扫车牌赢奖. 于是我就在上一个活动的基础上,将代码重新封装一下,并且将计算方式写的更 ...

随机推荐

  1. 关于统一资源标志符URL的理解

    URL由三部分构成 A:B:C A:URL使用的领域 B:在此领域的类型名称 C:标识资源的具体位置 C可以是一个绝对路径,也可以是端口号加上资源名称,总之是可以唯一标示资源的标识 例: 在网址中 S ...

  2. (29)网络编程之TCP通信协议

    TCP通信协议特点: 1.tcp协议是基于IO流进行数据的传输,是面向链接的. 2.tcp进行数据传输的时候,数据没有大小限制的. 3.面向链接,通过三次握手的机制,保证数据的完整性,是一个可靠的协议 ...

  3. 开源一个vue2的tree组件

    一直打算偷懒使用个现成的树组件,但是在github上找了一大圈没有找到真正满足应用开发的树组件,所以没办法只能自己写了一个,开源出来希望可以帮助到需要的人,同时如果大家觉得好用,我可以顺带骗骗★(希望 ...

  4. iOS9,10没有问题,iOS8上面一登录就崩溃,原因Assets的问题

    在项目中开发中,打包成一个ipa的包,发现iOS9,10,运行非常流畅,iOS8上面一运行就崩溃,找了好久,才找到原因竟然是Assets的问题,一开始我把ipa包放在蒲公英上面托管扫码下载的,用iTu ...

  5. 老李分享:curl发起https请求

    老李分享:curl发起https请求 在POPTEST上课的过程中,我们需要本地模拟https请求来完成性能测试,我们用curl来实现,curl是利用URL语法在命令行方式下工作的开源文件传输工具,使 ...

  6. bootstrap(响应式)加减输入框

    <div class="row">  <div class="col-lg-6">    <div class="inp ...

  7. PHP中的for循环

    循环 循环是操作某一个功能(执行某段代码). ①循环四要素: a 循环初始值 b 循环的条件 c 循环状态 d 循环体 ②for循环 a 穷举:把所有的可能性的都一一列出来. b 迭代:每次循环都会把 ...

  8. Android 布局(线性布局、相对布局)

    一.线性布局(LinearLayout) <LinearLayout****</LinearLayout>1. orientation(布局方向)value=0 horizontal ...

  9. jdk1.8新特性,还不知道的朋友还不看看,1.9都快出来了

    一.接口的默认方法 Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:代码如下:interface Formula {     ...

  10. JQuery处理DOM元素-属性操作

    JQuery处理DOM元素-属性操作 //操作元素的属性: $('*').each(function(n){ this.id = this.tagName + n; }) //获取属性值: $('') ...