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

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

打开一张图片

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

在图片上拖拽画框

画错了可以撤销(后退)

撤销了又想恢复(前进)

功能概述

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

核心实现思路

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();
  }
}
相关推荐
码上成长13 小时前
组件库提速:Storybook + Chromatic + Visual Test 实战
前端·自动化
灵犀坠13 小时前
前端核心知识体系梳理:从Vue 3到现代CSS与JavaScript
前端·javascript·vue.js
lcc18713 小时前
Vue3 新的组件
前端·vue.js
AskHarries13 小时前
技术人最深的三大痛点:看见的人不多,说出口的人更少
前端·后端·程序员
星尘库13 小时前
怎么实现js混淆加密 每隔一段时间 会失效 需要重新加密使用
java·服务器·前端
m***98213 小时前
Redis6.2.6下载和安装
android·前端·后端
LV技术派13 小时前
这一年,收获很多,办了婚礼,还出了一门前端AI课
前端·程序员·ai编程
我叫张小白。14 小时前
Vue3 基本生命周期:组件的一生之旅
前端·javascript·vue.js·前端框架·vue3
GISer_Jing14 小时前
SSE Conf大会分享——UTOO WASM:AI时代的浏览器原生极速研发套件
前端·人工智能·架构·wasm
Q***l68714 小时前
前端在移动端中的响应式设计
前端