前面曾经写过一篇《H5图片裁剪升级版》,但里面须要借助第三方手势库,此次就不须要使用手势库,所有封装在代码中。html
下图是裁剪的展现,下面就作了拖放和裁剪,没有作缩放,在插件中须要用到大量的计算。veImage的源码能够在此处浏览。git
1)拖动、缩放、裁剪都是借助Canvas实现的。Canvas的基础概念能够参考《让本身也能使用Canvas》。github
2)拖动是经过设置Canvas画布左上角的起点实现的。使用CanvasRenderingContext2D.translate方法。canvas
3)缩放是经过设置目标画布上绘制图像的宽度和高度实现的。使用CanvasRenderingContext2D.drawImage方法。ide
4)裁剪是经过计算比例后(效果图中的画布尺寸与实际网页中的画布尺寸不符),在原画布上面截取计算后的尺寸,画到一张新画布中,新画布的宽高就是须要截取的宽高。this
5)拖动、缩放是须要计算两个坐标的差值,而这两个坐标是经过e.touches获取到,这个参数能够参考《触屏touch事件记录》。spa
6)将画布的起始点,设置在画布的中心,也就是宽高的一半。这样设置后,缩放的效果看上去就是向四周缩放。不然效果是固定在图片左上角,而后缩放,以下图所示。插件
参数目前就3个。rest
1)Canvas:画布,能够经过DOM获取到。code
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}); };
拖动、缩放涉及的事件是touchstart,touchmove,touchend。
给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 );