移動端 H5圖片裁剪插件,內置簡單手勢操做

前面曾經寫過一篇《H5圖片裁剪升級版》,但裏面須要藉助第三方手勢庫,此次就不須要使用手勢庫,所有封裝在代碼中。html

下圖是裁剪的展現,下面就作了拖放和裁剪,沒有作縮放,在插件中須要用到大量的計算。veImage的源碼能夠在此處瀏覽git

1、原理

1)拖動縮放裁剪都是藉助Canvas實現的。Canvas的基礎概念能夠參考《讓本身也能使用Canvas》。github

2)拖動是經過設置Canvas畫布左上角的起點實現的。使用CanvasRenderingContext2D.translate方法。canvas

3)縮放是經過設置目標畫布上繪製圖像的寬度和高度實現的。使用CanvasRenderingContext2D.drawImage方法。ide

4)裁剪是經過計算比例後(效果圖中的畫布尺寸與實際網頁中的畫布尺寸不符),在原畫布上面截取計算後的尺寸,畫到一張新畫布中,新畫布的寬高就是須要截取的寬高。this

5)拖動縮放是須要計算兩個座標的差值,而這兩個座標是經過e.touches獲取到,這個參數能夠參考《觸屏touch事件記錄》。spa

6)將畫布的起始點,設置在畫布的中心,也就是寬高的一半。這樣設置後,縮放的效果看上去就是向四周縮放。不然效果是固定在圖片左上角,而後縮放,以下圖所示。插件

 

 

2、參數

參數目前就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});
};

 

3、事件綁定

拖動、縮放涉及的事件是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;
  }
};

 

4、拖動與縮放

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
);

 

5、畫圖

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
};

 

6、裁剪

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
);
相關文章
相關標籤/搜索