canvas绘制矩形选框裁剪图片,图片可放大缩小拖拽

canvas绘制矩形选框裁剪图片,图片可放大缩小拖拽

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    :root {
      --canvasWidth: 814px;
      --canvasHeight: 800px;
    }

    canvas {
      border: 1px solid black;
    }

    .canvas-box {
      width: 814px;
      height: 800px;
    }
  </style>
</head>

<body>
  <div class="canvas-box" style="width: var(--canvasWidth); height: var(--canvasHeight);">
    <canvas id="myCanvas" width="814" height="800"></canvas>
  </div>
  <div>
    <button onclick="zoomIn()">放大</button>
    <button onclick="zoomOut()">缩小</button>
    <button onclick="drag()">拖拽</button>
    <button onclick="select()">选取</button>
  </div>
  
  <script>
    var canvas = document.getElementById('myCanvas');
    var ctx = canvas.getContext('2d');
    var img = new Image();

    img.src = "./img/asd.png"; // 替换为你的图片路径
    var isDragging = false; // 是否按下了鼠标 默认没有
    var startX, startY, endX, endY;
    let scaleValue = 1 // 缩放比例
    let scaleDiff = 0.1 // 缩放递增值
    let imgWidth, imgHeight; // 图片的宽高
    let isInit = true // 判断是否是第一次绘制
    var containerWidth = canvas.width;
    var containerHeight = canvas.height;
    let imgObj = { x: 0, y: 0 } // 图片在canvas中的坐标

    let downDiffX, downDiffY // 鼠标按下时图片的差值 当前按下鼠标坐标-图片坐标
    let isSelect = false // 是否是选取框

    let drawRectArr = localStorage.getItem('drawRectArr') ? JSON.parse(localStorage.getItem('drawRectArr')) : []

    // 图片加载完毕后开始绘制
    img.onload = function () {
      imgWidth = img.width;
      imgHeight = img.height;

      let isUpright = imgWidth < imgHeight ? true : false // 判断图片是否为纵向 true 为纵向 false 为横向
      if (isInit && containerHeight < imgHeight && isUpright) { // 说明canvas高度小于了图片高度 
        scaleValue = containerHeight / imgHeight // 设置一下缩放比例
        isInit = false
      } else if (isInit && containerWidth < imgWidth && !isUpright) { // 说明canvas宽度小于了图片宽度
        scaleValue = containerWidth / imgWidth
        isInit = false
      }
      imgObj.x = (containerWidth - imgWidth * scaleValue) / 2 // 初始化时候图片居中 并设置x坐标
      imgObj.y = (containerHeight - imgHeight * scaleValue) / 2 // 初始化时候图片居中 并设置y坐标
      console.log(imgObj.x, imgObj.y)
      drawImageScaled();
    };

    function drawImageScaled() { // 绘制图片
      ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布
      ctx.drawImage(img, imgObj.x, imgObj.y, imgWidth * scaleValue, imgHeight * scaleValue);
    }
    // 监听滚轮事件
    canvas.addEventListener('wheel', function (event) {
      event.preventDefault();
      var delta = Math.sign(event.deltaY); // 判断滚轮方向,正值表示向下滚动,负值表示向上滚动
      if (delta > 0) {
        zoomOut()
      } else {
        zoomIn()
      }
    }, { passive: false });

    // 绘制矩形框
    function drawRect(x1, y1, x2, y2, color = 'blue') {
      ctx.strokeStyle = color;
      ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
    }
    // 鼠标按下事件
    canvas.addEventListener('mousedown', function (e) {
      isDragging = true;
      startX = e.offsetX; // 设置鼠标按下时的x坐标
      startY = e.offsetY; // 设置鼠标按下时的y坐标
      downDiffX = e.x - imgObj.x // 鼠标按下时鼠标距离图片左边的差值
      downDiffY = e.y - imgObj.y // 鼠标按下时鼠标距离图片上边的差值
    });
    // 鼠标移动事件
    canvas.addEventListener('mousemove', function (e) {
      if (!isDragging) return;
      if ( !isSelect) { // 选择框状态
        endX = e.offsetX;
        endY = e.offsetY;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        drawImageScaled();
        drawRect(startX, startY, endX, endY, 'red');
      } else {
        imgObj.x = e.x - downDiffX // 设置鼠标拖拽图片的距离
        imgObj.y = e.y - downDiffY // 设置鼠标拖拽图片的距离
        drawImageScaled()
      }

    });
    // 鼠标抬起事件
    canvas.addEventListener('mouseup', function () {
      let interceptObj = { // 设置默认数据
        cropStartX: preciseCalc(startX - imgObj.x, scaleValue, '/'), // 裁剪原图的起X坐标 
        cropStartY: preciseCalc(startY - imgObj.y, scaleValue, '/'), // 裁剪原图的起Y坐标
        cropEndX: preciseCalc(endX - imgObj.x, scaleValue, '/'), // 裁剪原图的结束X坐标
        cropEndY: preciseCalc(endY - imgObj.y, scaleValue, '/') // 裁剪原图的结束Y坐标
      }
      if (startX > endX) {  // 开始的起始坐标大于了结束x坐标 重新设置 cropEndX 和 cropstartX 解决了用户反向选取
        interceptObj.cropStartX = preciseCalc(endX - imgObj.x, scaleValue, '/'), // 裁剪原图的结束X坐标
          interceptObj.cropEndX = preciseCalc(startX - imgObj.x, scaleValue, '/')
      }
      if (startY > endY) { // 开始的起始坐标大于了结束y坐标 重新设置 cropEndY 和 cropstartY
        interceptObj.cropStartY = preciseCalc(endY - imgObj.y, scaleValue, '/')
        interceptObj.cropEndY = preciseCalc(startY - imgObj.y, scaleValue, '/')
      }
      drawRectArr.push(interceptObj)
      localStorage.setItem('drawRectArr', JSON.stringify(drawRectArr))

      isDragging = false;
      if (!isSelect) {
        cropImg(interceptObj)
      }
    });
    // 放大图片
    function zoomIn() {
      if (scaleValue < 3) { // 设置最大缩放限制
        scaleValue = preciseCalc(scaleValue, scaleDiff, '+')
        img.style.transform = `scale(${scaleValue})`;
      }
      drawImageScaled();
    }
    // 缩小图片
    function zoomOut() {
      if (scaleValue > 0.1) { // 设置最小缩放限制
        console.log(scaleValue)
        scaleValue = preciseCalc(scaleValue, scaleDiff, '-')
        console.log(scaleValue)
        img.style.transform = `scale(${scaleValue})`;
      }
      drawImageScaled();
    }
    // 点击拖拽
    function drag() {
      isSelect = true
    }
    // 点击选取框
    function select() {
      isSelect = false
    }
    // 加法运算避免精度丢失
    function preciseCalc(num1, num2, operator = '+') {
      const precision = 10 ** 10; // 设定精度,根据需要调整
      switch (operator) {
        case '+':
          // console.log(num1, num2)
          return  parseFloat((Math.round(num1 * precision) + Math.round(num2 * precision)) / precision);
        case '-':
          return  parseFloat((Math.round(num1 * precision) - Math.round(num2 * precision)) / precision);
        case '/':
          return  parseFloat((num1 / num2).toFixed(2));
        default:
          throw new Error('Unsupported operation');
      }
    }
    // 图片截取
    const cropImg = ({ cropStartX, cropStartY, cropEndX, cropEndY }) => {
      const cropCanvas = document.createElement('canvas')
      cropCanvas.width = cropEndX - cropStartX
      cropCanvas.height = cropEndY - cropStartY
      const ctx = cropCanvas.getContext('2d')
      ctx.drawImage(img, cropStartX, cropStartY, cropCanvas.width, cropCanvas.height, 0, 0, cropCanvas.width, cropCanvas.height)
      img.crossOrigin = "anonymous"; 
      console.log(cropCanvas.toDataURL()) // 截图图片的base64地址
      document.body.appendChild(cropCanvas)
    }
    
  </script>
</body>

</html>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值