canvas实现图片标注,绘制区域

使用canvas绘制通过多边形标注区域

AI视频项目中需要分析图片,需要前台绘制区域,后端获取坐标然后识别图像,通过canvas

获取点然后连线绘图

 HEML代码段
   <div class="areaDrawing">
      <img src="@/assets/images/snapPhotos.png" />
      <canvas ref="canvas" style="position: absolute; top: 0; left: 0;" :width="canvasWidth"
        :height="canvasHeight"></canvas>
    </div>
 CSS代码段
.areaDrawing {
  position: relative;
  width: 400px; // 绘图区域宽度
  height: 300px; // 绘图区域高度

  img {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
  }
}
 script代码段
<script>
// 脚本开始
export default {
  data() {
    return {
      canvasWidth: 400, // 画布的宽度
      canvasHeight: 300, // 画布的高度
      imageSrc: 'your_image_url_here', // 图像的URL地址
      context: null, // 画布上下文
      points: [], // 用于存储点的数组
      isDragging: false, // 是否正在拖拽
      draggingIndex: -1, // 当前拖拽的点的索引
      Drawing: false,//控制绘制
    };
  },
  methods: {
    // 处理点击事件,用于添加新点
    handleCanvasClick(event) {
      console.log(this.points.length, 'this.points.length');
      // 检查是否开启绘制
      if (!this.Drawing || this.points.length >= 4) {
        return;
      }

      // 获取点击点的坐标
      const rect = this.$refs.canvas.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;

      // 检查是否有重复点
      const isDuplicate = this.points.some(point => {
        return Math.abs(point.x - x) < 5 && Math.abs(point.y - y) < 5;
      });

      // 如果没有重复点,则添加新点并重新绘制
      if (!isDuplicate) {
        this.points.push({ x, y });
        this.redraw();
      }

      // 如果点的数量大于等于4个,则绘制多边形
      if (this.points.length >= 4) {
        this.drawPolygon(this.points);
      }
    },
    // 处理鼠标按下事件
    handleMouseDown(event) {
      if (this.Drawing) {
        return
      }
      // 获取鼠标按下点的坐标
      const rect = this.$refs.canvas.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;

      // 查找当前拖拽的点的索引
      this.draggingIndex = this.points.findIndex(point => {
        return Math.abs(point.x - x) < 5 && Math.abs(point.y - y) < 5;
      });

      // 如果存在拖拽的点,则设置拖拽状态为true
      if (this.draggingIndex !== -1) {
        this.isDragging = true;
      }
    },
    // 处理鼠标移动事件
    handleMouseMove(event) {
      // 如果正在拖拽,则更新当前拖拽点的坐标并重新绘制
      if (this.isDragging) {
        const rect = this.$refs.canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;
        this.points[this.draggingIndex].x = x;
        this.points[this.draggingIndex].y = y;
        this.redraw();
      }
    },
    // 处理鼠标释放事件
    handleMouseUp() {
      // 重置拖拽状态和拖拽点的索引
      this.isDragging = false;
      this.draggingIndex = -1;
    },
    // 绘制点
    drawPoint(x, y) {
      this.context.beginPath();
      this.context.arc(x, y, 5, 0, 2 * Math.PI, false);
      this.context.fillStyle = 'blue';
      this.context.fill();
      this.context.lineWidth = 1;
      this.context.strokeStyle = 'blue';
      this.context.stroke();
    },
    // 重新绘制画布
    redraw() {
      // 清空画布
      this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      // 绘制多边形
      this.drawPolygon(this.points);

      // 绘制所有点,并连接相邻点
      this.points.forEach((point, index) => {
        this.drawPoint(point.x, point.y);
        if (index > 0) {
          this.context.beginPath();
          this.context.moveTo(this.points[index - 1].x, this.points[index - 1].y);
          this.context.lineTo(point.x, point.y);
          this.context.strokeStyle = 'blue';
          this.context.lineWidth = 1;
          this.context.stroke();
        }
      });

      // 连接第一个点和最后一个点,形成闭合的多边形
      if (this.points.length > 3) {
        this.context.beginPath();
        this.context.moveTo(this.points[this.points.length - 1].x, this.points[this.points.length - 1].y);
        this.context.lineTo(this.points[0].x, this.points[0].y);
        this.context.strokeStyle = 'blue';
        this.context.lineWidth = 1;
        this.context.stroke();
      }
    },
    // 绘制多边形
    drawPolygon(points) {
      if (points.length >= 2) {
        this.context.beginPath();
        this.context.moveTo(points[0].x, points[0].y);
        for (let i = 1; i < points.length; i++) {
          this.context.lineTo(points[i].x, points[i].y);
        }
        if (points.length === 4) {
          this.context.closePath();
          this.context.strokeStyle = 'red';
          this.context.lineWidth = 2;
          this.context.stroke();
        }
      }
    },
    // 动画方法,用于拖拽时重新绘制画布
    animate() {
      if (this.isDragging) {
        this.redraw();
        requestAnimationFrame(this.animate);
      }
    },
    //开始绘制
    handleDrawing() {
      this.Drawing = true;
    },
    //绘制微调
    resetDrawing() {
      this.Drawing = false;
    },
    //清除绘制
    clearDrawing() {
      this.points.length = 0;
      this.redraw()
    },

  },
  mounted() {
    // 获取画布上下文
    this.context = this.$refs.canvas.getContext('2d');
    // 添加事件监听器
    this.$refs.canvas.addEventListener('click', this.handleCanvasClick);
    this.$refs.canvas.addEventListener('mousedown', this.handleMouseDown);
    this.$refs.canvas.addEventListener('mousemove', this.handleMouseMove);
    this.$refs.canvas.addEventListener('mouseup', this.handleMouseUp);
    this.$refs.canvas.addEventListener('mouseleave', this.handleMouseUp);
    // 绑定动画方法的上下文
    this.animate = this.animate.bind(this);
  },
};
// 脚本结束
</script>

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
实现 Canvas 上的图片标注、缩放、移动、保存历史状态、橡皮擦等功能,可以通过以下步骤来完成: 1. 加载图片。使用 JavaScript 中的 Image 对象加载图片,并在图片加载完成后将其绘制Canvas 上。 ```javascript const img = new Image(); // 创建 Image 对象 img.onload = function() { ctx.drawImage(img, 0, 0); // 将图片绘制到画布上 }; img.src = 'image.jpg'; // 设置图片路径 ``` 2. 实现标注功能。通过鼠标事件监听用户的操作,使用 Canvas 的 API 绘制标注。例如,监听鼠标点击事件,在点击位置绘制一个圆形。 ```javascript canvas.addEventListener('mousedown', function(e) { ctx.beginPath(); ctx.arc(e.offsetX, e.offsetY, 5, 0, 2 * Math.PI); ctx.fill(); }); ``` 3. 实现缩放和移动功能。通过鼠标滚轮事件监听用户的操作,使用 Canvas 的 API 实现缩放和移动。例如,监听鼠标滚轮事件,在滚轮滚动时根据滚动方向调整画布的缩放比例。 ```javascript canvas.addEventListener('wheel', function(e) { const delta = e.deltaY > 0 ? 0.1 : -0.1; const scale = Math.max(0.1, Math.min(10, currentScale + delta)); ctx.scale(scale, scale); currentScale = scale; }); ``` 4. 实现保存历史状态功能。使用 JavaScript 中的数组来保存历史状态,每当用户进行操作时,将当前状态保存到数组中。撤销操作时,从数组中取出上一个状态并恢复到画布上。 ```javascript const states = []; // 保存历史状态的数组 function saveState() { states.push(canvas.toDataURL()); // 保存当前状态 } function undo() { if (states.length > 0) { const img = new Image(); img.onload = function() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布 ctx.drawImage(img, 0, 0); // 绘制上一个状态 }; img.src = states.pop(); // 取出上一个状态 } } ``` 5. 实现橡皮擦功能。通过监听鼠标事件,在鼠标位置绘制一个与背景相同的矩形,来模拟橡皮擦的效果。 ```javascript canvas.addEventListener('mousemove', function(e) { if (erasing) { ctx.fillStyle = '#ffffff'; // 设置橡皮擦颜色为白色 ctx.fillRect(e.offsetX - 5, e.offsetY - 5, 10, 10); // 绘制矩形 } }); ``` 完整示例代码如下: ```html <!DOCTYPE html> <html> <body> <canvas id="canvas" width="600" height="400"></canvas> <button onclick="undo()">撤销</button> <button onclick="erasing = !erasing">橡皮擦</button> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let currentScale = 1; let erasing = false; const states = []; const img = new Image(); img.onload = function() { ctx.drawImage(img, 0, 0); saveState(); }; img.src = 'image.jpg'; canvas.addEventListener('mousedown', function(e) { ctx.beginPath(); ctx.arc(e.offsetX, e.offsetY, 5, 0, 2 * Math.PI); ctx.fill(); saveState(); }); canvas.addEventListener('mousemove', function(e) { if (erasing) { ctx.fillStyle = '#ffffff'; ctx.fillRect(e.offsetX - 5, e.offsetY - 5, 10, 10); } }); canvas.addEventListener('wheel', function(e) { const delta = e.deltaY > 0 ? 0.1 : -0.1; const scale = Math.max(0.1, Math.min(10, currentScale + delta)); ctx.scale(scale, scale); currentScale = scale; }); function saveState() { states.push(canvas.toDataURL()); } function undo() { if (states.length > 1) { const img = new Image(); img.onload = function() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0); }; img.src = states[states.length - 2]; states.pop(); } } </script> </body> </html> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农六六

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值