前面曾經寫過一篇《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 );