前端 图片上鼠标画矩形框,标注文字,任意删除
效果:
页面描述:
对给定的几张图片,每张能用鼠标在图上画框,标注相关文字,框的颜色和文字内容能自定义改变,能删除任意画过的框。
实现思路:
1、对给定的这几张图片,用分页器绑定展示,能选择图片;
2、图片上绑定事件@mousedown鼠标按下——开始画矩形、@mousemove鼠标移动——绘制中临时画矩形、@mouseup鼠标抬起——结束画矩形重新渲染;
开始画矩形:鼠标按下,记录鼠标按下的位置。遍历标签数组,找到check值为true的标签,用其样式和名字创建新的标签,加入该图片的矩形框们的数组。注意,监听鼠标如果是按下后马上抬起,结束标注。
更新矩形:识别到新的标签存在,鼠标移动时监听移动距离,更新当前矩形宽高,用canvas绘制实时临时矩形。
结束画矩形:刷新该图片的矩形框们的数组,触发重新渲染。
3、在图片上v-for遍历渲染矩形框,盒子绑定动态样式改变宽高;
4、右侧能添加、修改矩形框颜色和文字;
5、列举出每个矩形框名称,能选择进行删除,还能一次清空;
清空{{ annotation.label }} 标签 添加 数据 {{ index + 1 }}.{{ annotation.name }} import { DeleteOutlined } from '@ant-design/icons-vue'; import { Pagination } from 'ant-design-vue'; interface State { tagsList: any; canvasX: number; canvasY: number; currentPage: number; pageSize: number; imageUrls: string[]; }; const state = reactive({ tagsList: [], // 标签列表 canvasX: 0, canvasY: 0, currentPage: 1, pageSize: 1, imageUrls: [apiUrl.value + '/api/File/Image/annexpic/20241203Q9NHJ.jpg', apiUrl.value + '/api/file/Image/document/20241225QBYXZ.jpg'], }); interface Annotation { id: string; name: string; x: number; y: number; width: number; height: number; color: string; label: string; border: string; }; const annotations = reactive>([[]]); let currentAnnotation: Annotation | null = null; //开始标注 function startAnnotation(event: MouseEvent) { // 获取当前选中的标签 var tagsCon = { id: 1, check: true, color: '#000000', name: '安全帽' }; // 遍历标签列表,获取当前选中的标签 for (var i = 0; i { endAnnotation(); window.removeEventListener('mouseup', mouseupHandler); }; window.addEventListener('mouseup', mouseupHandler); } //更新标注 function updateAnnotation(event: MouseEvent) { if (currentAnnotation) { //更新当前标注的宽高,为负数时,鼠标向左或向上移动 currentAnnotation.width = event.offsetX - currentAnnotation.x; currentAnnotation.height = event.offsetY - currentAnnotation.y; } //如果正在绘制中,更新临时矩形的位置 if (annotationCanvas.value) { const canvas = annotationCanvas.value; //取得类名为image-container的div的宽高 const imageContainer = document.querySelector('.image-container'); canvas.width = imageContainer?.clientWidth || 800; canvas.height = imageContainer?.clientHeight || 534; const context = canvas.getContext('2d'); if (context) { context.clearRect(0, 0, canvas.width, canvas.height); context.strokeStyle = currentAnnotation?.border || '#000000'; context.lineWidth = 2; context.strokeRect(state.canvasX, state.canvasY, currentAnnotation?.width || 0, currentAnnotation?.height || 0); } } } function endAnnotation() { //刷新annotations[state.currentPage - 1],触发重新渲染 annotations[state.currentPage - 1] = annotations[state.currentPage - 1].slice(); currentAnnotation = null; } function annotationStyle(annotation: Annotation) { //如果宽高为负数,需要调整left和top的位置 const left = annotation.width { if (index === index2) { item.check = true; } else { item.check = false; } }); } // 删除标签 function deleteTag(index: number) { state.tagsList.splice(index, 1); } function addTags() { state.tagsList.push({ id: state.tagsList.length + 1, check: false, color: '#000000', name: '' }); } // 移除某个标注 function removeAnnotation(id: string) { const index = annotations[state.currentPage - 1].findIndex(a => a.id === id); if (index !== -1) { annotations[state.currentPage - 1].splice(index, 1); } } // 清空所有标注 function clearAnnotations() { annotations[state.currentPage - 1].splice(0, annotations[state.currentPage - 1].length); } onMounted(() => { for (let i = 0; i
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。