1. 程式人生 > 實用技巧 >canvas圖片編輯操作:縮放、移動、儲存(PC端+移動端)

canvas圖片編輯操作:縮放、移動、儲存(PC端+移動端)

最近在寫canvas關於圖片的操作,看了網上的程式碼基本都是不行的,於是就自己寫了一個。

html程式碼

  <canvas id="myCanvas" width="375px" height="500px"></canvas>
  <a id="save">
    點選儲存
  </a>

移動端操作: Js程式碼

    var canvas = document.getElementById('myCanvas'); //畫布物件
    var context = canvas.getContext('2d'); //畫布顯示二維圖片
    var saveBtn = document.getElementById('save');
    var img, //圖片是否載入完成;
      imgX = 0,
      imgY = 0,
      dragging = false,
      posl = {},
      scale = 1,
      pos = {
        x: 0,
        y: 0
      },
      newPos = {
        x: 0,
        y: 0
      };

    loadImg();

    function drawImage(params) {
      context.clearRect(0, 0, canvas.width, canvas.height);
      // 保證 imgX 在 [img.width*(1-scale),0] 區間內
      if (imgX < img.width * (1 - scale)) {
        imgX = img.width * (1 - scale);
      } else if (imgX > 0) {
        imgX = 0
      }
      // 保證 imgY 在 [img.height*(1-scale),0] 區間內
      if (imgY < img.height * (1 - scale)) {
        imgY = img.height * (1 - scale);
      } else if (imgY > 0) {
        imgY = 0
      }
      context.drawImage(
        img, //規定要使用的影象、畫布或視訊。
        0, 0, //開始剪下的 x 座標位置。
        img.width, img.height, //被剪下影象的高度。
        imgX, imgY, //在畫布上放置影象的 x 、y座標位置。
        img.width * scale, img.height * scale //要使用的影象的寬度、高度
      );
    }

    function loadImg() {
      img = new Image();
      img.onload = function () {
        drawImage();
      }
      img.src = './test.jpg'
    }
    var start, end = 0;
    canvas.addEventListener('touchstart', function (e) {
      e.preventDefault()
      if (e.touches.length === 1) {
        dragging = true;
        pos = windowToCanvas(e.touches[0].clientX, e.touches[0].clientY); //座標轉換,將視窗座標轉換成canvas的座標
      }
      if (e.touches.length === 2) {
        var t1 = e.touches[0];
        var t2 = e.touches[1];
        var pos1 = {
          x: t1.clientX,
          y: t1.clientY
        }
        var pos2 = {
          x: t2.clientX,
          y: t2.clientY
        }
        pos = windowToCanvas((pos1.x + pos2.x) / 2, (pos1.y + pos2.y) / 2);
      }
    });
    canvas.addEventListener('touchmove', function (e) {
      e.preventDefault()
      if (e.touches.length === 1) {
        // 加上dragging區分pos和posl的值,一個為雙指,這裡為單指的值
        if (dragging) {
          posl = windowToCanvas(e.touches[0].clientX, e.touches[0].clientY);
          var x = posl.x - pos.x;
          var y = posl.y - pos.y;
          imgX += x;
          imgY += y;
          pos = JSON.parse(JSON.stringify(posl));
          drawImage(); //重新繪製圖片
        }
      }
      // 雙指中有可能存在移動,所以不加dragging判斷,都是用的同一個中心點
      if (e.touches.length === 2) {
        posl = JSON.parse(JSON.stringify(pos));
        var s1 = end;
        var t1 = e.touches[0];
        var t2 = e.touches[1];
        var pos1 = {
          x: t1.clientX,
          y: t1.clientY
        }
        var pos2 = {
          x: t2.clientX,
          y: t2.clientY
        }
        pos = windowToCanvas((pos1.x + pos2.x) / 2, (pos1.y + pos2.y) / 2);
        end = Math.sqrt(Math.pow((pos1.x - pos2.x), 2) + Math.pow((pos1.y - pos2.y), 2));
        var pianX = posl.x - pos.x;
        var pianY = posl.y - pos.y;

        newPos = {
          x: ((pos.x - imgX + pianX) / scale),
          y: ((pos.y - imgY + pianY) / scale)
        };
        // 縮小
        if (s1 > end) {
          scale = scale - 0.05;
          imgX = (1 - scale) * newPos.x + (pos.x -
            newPos.x);
          imgY = (1 - scale) * newPos.y + (pos.y - newPos.y);
          if (scale < 1) { //最小縮放1
            scale = 1;
            drawImage(); //重新繪製圖片
            return
          }
          // drawImage(); //重新繪製圖片
          // 放大
        } else {
          scale = scale + 0.05;
          imgX = (1 - scale) * newPos.x + (pos.x -
            newPos.x);
          imgY = (1 - scale) * newPos.y + (pos.y - newPos.y);
          // drawImage();
        }
        drawImage();

      }
    });
    canvas.addEventListener('touchend', function (e) {
      e.preventDefault()
      if (e.touches.length === 1) {
        dragging = false;
      }
    })
    saveBtn.addEventListener('click', function (e) {
      var imgUrl = canvas.toDataURL();
      var imgName = prompt('下載的圖片名稱:');
      if (imgName != null) {
        saveBtn.download = imgName;
        saveBtn.href = imgUrl;
      }
    })


    function windowToCanvas(x, y) {
      var box = canvas.getBoundingClientRect();
      //這個方法返回一個矩形物件,包含四個屬性:left、top、right和bottom。分別表示元素各邊與頁面上邊和左邊的距離
      return {
        x: x - box.left - (box.width - canvas.width) / 2,
        y: y - box.top - (box.height - canvas.height) / 2
      };
    }

 PC端操作: Js程式碼

    var canvas = document.getElementById('scaleDragCanvas'); //畫布物件
    var context = canvas.getContext('2d'); //畫布顯示二維圖片
    var saveBtn = document.getElementById('save');
    var img, imgX = 0,
      imgY = 0,
      imgScale = 1;
    var MINIMUM_SCALE = 1.0,
      pos = {},
      posl = {},
      dragging = false;

    loadImg();
    canvasEventsInit();

    function loadImg() {
      img = new Image();
      img.onload = function () {
        drawImage();
      }
      img.src =
        './test.jpg';
    }

    function drawImage() {
      context.clearRect(0, 0, canvas.width, canvas.height);
      // 保證 imgX 在 [img.width*(1-imgScale),0] 區間內
      if (imgX < img.width * (1 - imgScale)) {
        imgX = img.width * (1 - imgScale);
      } else if (imgX > 0) {
        imgX = 0
      }
      // 保證 imgY 在 [img.height*(1-imgScale),0] 區間內
      if (imgY < img.height * (1 - imgScale)) {
        imgY = img.height * (1 - imgScale);
      } else if (imgY > 0) {
        imgY = 0
      }
      context.drawImage(
        img, //規定要使用的影象、畫布或視訊。
        0, 0, //開始剪下的 x 座標位置。
        img.width, img.height, //被剪下影象的高度。
        imgX, imgY, //在畫布上放置影象的 x 、y座標位置。
        img.width * imgScale, img.height * imgScale //要使用的影象的寬度、高度
      );
    }

    /*事件註冊*/
    function canvasEventsInit() {
      canvas.onmousedown = function (event) {
        dragging = true;
        pos = windowToCanvas(event.clientX, event.clientY); //座標轉換,將視窗座標轉換成canvas的座標
      };
      saveBtn.addEventListener('click', function (e) {
        var imgUrl = canvas.toDataURL();
        var imgName = prompt('下載的圖片名稱:');
        if (imgName != null) {
          saveBtn.download = imgName;
          saveBtn.href = imgUrl;
        }
      })
      canvas.onmousemove = function (evt) { //移動
        if (dragging) {
          posl = windowToCanvas(evt.clientX, evt.clientY);
          var x = posl.x - pos.x,
            y = posl.y - pos.y;
          imgX += x;
          imgY += y;
          pos = JSON.parse(JSON.stringify(posl));
          drawImage(); //重新繪製圖片
        }
      };
      canvas.onmouseup = function () {
        dragging = false;
      };
      canvas.onmousewheel = canvas.onwheel = function (event) { //滾輪放大縮小
        var pos = windowToCanvas(event.clientX, event.clientY);
        console.log(pos)
        event.wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltalY * (-40)); //獲取當前滑鼠的滾動情況
        var newPos = {
          x: ((pos.x - imgX) / imgScale).toFixed(2),
          y: ((pos.y - imgY) / imgScale).toFixed(2)
        };
        if (event.wheelDelta > 0) { // 放大
          imgScale += 0.1;
          imgX = (1 - imgScale) * newPos.x + (pos.x - newPos.x);
          imgY = (1 - imgScale) * newPos.y + (pos.y - newPos.y);
        } else { // 縮小
          imgScale -= 0.1;
          if (imgScale < MINIMUM_SCALE) { //最小縮放1 
            imgScale = MINIMUM_SCALE;
          }
          imgX = (1 - imgScale) * newPos.x + (pos.x - newPos.x);
          imgY = (1 - imgScale) * newPos.y + (pos.y - newPos.y);
          console.log(imgX, imgY);
        }
        drawImage(); //重新繪製圖片 }; } /*座標轉換*/
      }
    }

    function windowToCanvas(x, y) {
      var box = canvas.getBoundingClientRect();
      //這個方法返回一個矩形物件,包含四個屬性:left、top、right和bottom。分別表示元素各邊與頁面上邊和左邊的距離
      return {
        x: x - box.left - (box.width - canvas.width) / 2,
        y: y - box.top - (box.height - canvas.height) / 2
      };
    }