仿一下微信的截图标注功能

就像用画图软件在图片上画框框:

打开一张图片

选择红色/黄色/蓝色框框

在图片上拖拽画框

画错了可以撤销(后退)

撤销了又想恢复(前进)

功能概述

这个工具允许用户在图片上进行矩形标注,支持三种不同类型的标注,并提供前进/后退功能来撤销或重做操作。

核心实现思路

1. 数据结构设计

typescript 复制代码
export interface MarkerType {
  x: number,        // 标记左上角x坐标
  y: number,        // 标记左上角y坐标
  height: number,   // 标记高度
  width: number,    // 标记宽度
  type: "1" | "2" | "3"  // 标记类型
}

export interface ImgMarkerType {
  img: string,      // 图片地址
  markList: MarkerType[]  // 标记列表
}

2. 关键状态管理

typescript 复制代码
// 图片标注数据
const imgMarkerData = reactive<ImgMarkerType>({
  img: url,
  markList: []
});

// 当前标注类型
const nowType = ref<"1" | "2" | "3">("1");

// 当前操作索引(用于前进后退)
const nowIndex = ref(0);

// 是否可以绘制(鼠标按下时)
const canDraw = ref(false);

3. 核心功能实现

3.1 渲染画布

typescript 复制代码
function renderCanvas() {
  if (!ctx.value) return;
  
  // 清空画布
  ctx.value.clearRect(0, 0, 800, 800);
  
  // 绘制图片
  if (img.value) {
    ctx.value.drawImage(img.value, 0, 0, 800, 800);
  }
  
  // 绘制标记
  imgMarkerData.markList.forEach((marker, index) => {
    if (index > nowIndex.value) return; // 前进后退控制
    
    // 根据类型设置颜色
    const colorMap = {
      "1": "red",
      "2": "yellow", 
      "3": "blue"
    };
    
    ctx.value!.strokeStyle = colorMap[marker.type];
    ctx.value!.strokeRect(marker.x, marker.y, marker.width, marker.height);
  });
}

3.2 鼠标事件处理

typescript 复制代码
function mousedown(e: MouseEvent) {
  canDraw.value = true;
  
  // 创建新标记
  const rect = (e.target as HTMLCanvasElement).getBoundingClientRect();
  const newMarker: MarkerType = {
    x: e.clientX - rect.left,
    y: e.clientY - rect.top,
    width: 0,
    height: 0,
    type: nowType.value
  };
  
  imgMarkerData.markList.push(newMarker);
  nowIndex.value = imgMarkerData.markList.length - 1;
}

function mousemove(e: MouseEvent) {
  if (!canDraw.value) return;
  
  const rect = (e.target as HTMLCanvasElement).getBoundingClientRect();
  const currentX = e.clientX - rect.left;
  const currentY = e.clientY - rect.top;
  
  // 更新当前标记的尺寸
  const currentMarker = imgMarkerData.markList[nowIndex.value];
  currentMarker.width = currentX - currentMarker.x;
  currentMarker.height = currentY - currentMarker.y;
  
  renderCanvas(); // 重新渲染
}

function mouseup() {
  canDraw.value = false;
  renderCanvas(); // 最终渲染
}

3.3 前进后退功能

typescript 复制代码
function goBack() {
  if (nowIndex.value > 0) {
    nowIndex.value--;
    renderCanvas();
  }
}

function goForward() {
  if (nowIndex.value < imgMarkerData.markList.length - 1) {
    nowIndex.value++;
    renderCanvas();
  }
}
相关推荐
cmd1 分钟前
吃透 ES6 Generator:yield/next/yield* 核心用法详解
前端·javascript
我叫黑大帅2 分钟前
🎯 DOM 事件:onclick VS addEventListener('click')区别
前端·javascript·面试
踩着两条虫5 分钟前
AI 驱动的 Vue3 应用开发平台 深入探究(二十二):CLI与工具链之开发与生产工作流
前端·vue.js·ai编程
Ankkaya8 分钟前
大师助我,electron-hiprint 源码梳理
前端·vue.js
风止何安啊8 分钟前
🪝 别再重复造轮子了!教你偷懒:在 React 自定义 Hook
前端·react.js·面试
踩着两条虫8 分钟前
AI 驱动的 Vue3 应用开发平台 深入探究(二十三):API与参考之Engine API 参考
前端·vue.js·ai编程
Moment10 分钟前
开源一年,我的 AI 全栈项目 AI 协同编辑器终于有 1.1 k star了 😍😍😍
前端·后端·面试
爱学习的小囧10 分钟前
VCF 集群部署灵活组合:单节点与高可用配置完全指南
java·服务器·前端
967713 分钟前
AJAX和Axios理解和关系
前端·ajax·okhttp
sg_knight16 分钟前
Claude Code 如何辅助定位 Bug 和问题代码
java·前端·bug·ai编程·claude·code·claude-code