前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Vue + fabric.js的图片标注组件搭建

基于Vue + fabric.js的图片标注组件搭建

原创
作者头像
扬起
发布2022-06-28 10:19:44
5.3K1
发布2022-06-28 10:19:44
举报
文章被收录于专栏:dongdong的数据标注

需求收集

做这个组件的初衷,是基于AI组的标注识别,传送一张图片以及图片上的一些坐标,返回对应的识别结果,前端要做的就是基于一张图片,在图片上绘制出相应的标注框,并将标注框对应的坐标以及宽高传送给后端进行识别,这是最基础的需求。在图片上进行绘制,首先想到的是用canvascancas强大的功能能让我们在图片上为所欲为,原生的canvasapi众多且繁杂,上手不易,fabric是一个基于canvas的强大的框架,提供一种类似面向对象的方法来编写canva,在原生canvas之上提供了交互式对象模型,通过简洁的api就可以在画布上进行丰富的操作。因此选择fabric来作为基础框架。

fabric.js介绍

fabric是基于canvas进行的api封装,可以实现绘制矩形、圆、椭圆、文本等一些基础图形,同时支持画笔自定义图形,fabric的优点在于它对生成的canvas画布进行了良好的封装,包括对画布以及画布上的对象进行调整,监听画布和对象的各种事件,使得画布交互逻辑变得简单易上手。fabric官网详细地列出了fabric的各种参数以及api,由于Fabric.js是国外的框架,文档为全英文,且相关示例少,所以建议配合源码使用

功能

构建画布

代码语言:javascript
复制
此处参考:https://github.com/EmilyZhang123/vue-label-me

  1. 根据图片生成基础画布

首先组件从外部接收图片链接

代码语言:javascript
复制
props:{
    imgData: String  // 图片链接
}

watch监听imageData变化,并生成画布

代码语言:javascript
复制
watch:{
    imageData(val){
        if(val){
            this.fabricCanvas() // 生成画布
         }
     }
}

fabricCanvas事件主要是初始化fabric,并将图片设置成画布的背景图片,以便后续在画布上添加标注框

代码语言:javascript
复制
<template>
    <div id="canvax-box">
        <canvas id="label-canvas" :width="width" :height="height">
    </div>
</template>
代码语言:javascript
复制
<script>
 export default{
     methods:{
         fabricCanvas(){
             if(this.fabricObj){ // 如果画布已经存在,清空画布重新绘制
                 this.fabricObj.clear()
             } else {
                 this.fabricObj = new fabric.Canvas('lavel-canvas',{
                 // 此处设置画布的初始属性
                 uniformScaling: false, // 等比例缩放
                 enableRetinaScaling: false, 
                 selection: false // 禁止组选择
                 }
             }
             let Shape
             const image = new Image()
             image.src = this.imageData
             image.setAttribute('crossOrigin','anonymous') // 允许跨域访问
             image.onload = () => {
                 // 将canvas的width和height设置成图片的原始width,height
                 this.width = image.width 
                 this.height = image.height
                 this.fabricObj.setWidth(this.width)
                 this.fabricObj.setHeight(this.height)
                 // 将图片放置在外部容器中
                 let boxWidth = document.getElementById('canvas-box').offsetWidth
                 let boxHeight = document.getElementById('canvas-box').offsetHeight
                 let scaleX = boxWidth / image.width
                 let scaleY = boxHeight / image.height
                 // 确定缩放因子
                 this.scale = scaleX > scaleY ? scaleX : scaleY
                 document.querySelector('.canvas-container').style.width = this.width * this.scale + 'px'
                 document.querySelector('.canvas-container').style.height = this.height * this.scale + 'px'
                 document.querySelector('#label-canvas').style.width = this.width * this.scale + 'px'
                 document.querySelector('#label-canvas').style.height = this.height * this.scale + 'px'
                 document.querySelector('.upper-canvas').style.width = this.width * this.scale + 'px'
                 document.querySelector('.upper-canvas').style.height = this.height * this.scale + 'px'
                 
                 Shape = new fabric.Image(image)
                 this.fabric.setBackgroundImage(Shape,
                     this.fabricObj.renderAll.bind(this.fabricObj),
                     {
                         opaity: 1,
                         angle: 0
                     }
                 )
                 this.$nextTick(()=>{
                     this.fabricObj.renderAll() // 重新渲染画布
                 })
             }
         }
     }
 }
</script>
  1. 监听画布事件 fabric提供了一系列的事件帮助我们来很好的对画布进行各种操作

此次主要用到以下几个事件

代码语言:javascript
复制
watch:{
 imageData(val){
     if(val){
         this.fabricCanvas() // 生成画布
         this.fabricObjEvent() // 监听画布事件
      }
  }
}

画布操作

标注画框

标注画框主要用到的是上述中的mouse:down:画笔落下;mouse:move画框;mouse:up画笔抬起事件

调整画框

在调整画框之前,首先要将画布设置为可选择

如果想要修改画框的默认选中样式,可修改画框的对应参数即可

调整画框主要用到上述的object:moving:对象移动;object:modified:对象调整;

代码语言:javascript
复制
handleObjectMoving(){

// 阻止对象移动到画布外面
      let padding = 0; // 内容距离画布的空白宽度,主动设置
      var obj = e.target;
      if (obj.currentHeight > obj.canvas.height - padding * 2 ||
        obj.currentWidth > obj.canvas.width - padding * 2) {
        return;
      }
      obj.setCoords();
      if (obj.getBoundingRect().top < padding || obj.getBoundingRect().left < padding) {
        obj.top = Math.max(obj.top, obj.top - obj.getBoundingRect().top + padding);
        obj.left = Math.max(obj.left, obj.left - obj.getBoundingRect().left + padding);
      }
      if (obj.getBoundingRect().top + obj.getBoundingRect().height > obj.canvas.height - padding || obj.getBoundingRect().left + obj.getBoundingRect().width > obj.canvas.width - padding) {
        obj.top = Math.min(
          obj.top,
          obj.canvas.height - obj.getBoundingRect().height + obj.top - obj.getBoundingRect().top - padding
        );
        obj.left = Math.min(
          obj.left,
          obj.canvas.width - obj.getBoundingRect().width + obj.left - obj.getBoundingRect().left - padding
        );
      }

}
代码语言:javascript
复制
handleObjectModified(e){
this.$emit('objectModified',e.target)
}
选中画框

画框被选中时,可抛出选中事件

代码语言:javascript
复制
// rect setRect()方法中生成的画框
rect.on('selected',(e)=>{
    this.$emit('objectSelected', e.target)
})
删除画框

调用fabric的remove事件即可

代码语言:javascript
复制
this.fabricObj.remove(item)
清空所有画框
代码语言:javascript
复制
clearAllMark(){
    const objects = this.fabricObj.getObjects()
    for(let i in objects){
        this.fabricObj.remove(i)
    }
    this.$emit('clearAllMark')
}
根据坐标生成画框
  1. 生成单个画框
  1. 批量生成

预览

代码语言:javascript
复制
此处参考 https://github.com/Dark2017/vue-dark-photo

使用css的transform来对画布进行放大缩小和拖拽操作

放大缩小

  1. 放大

2. 缩小

3. 还原

拖拽

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需求收集
  • fabric.js介绍
  • 功能
    • 构建画布
      • 画布操作
        • 标注画框
        • 调整画框
      • 预览
        • 放大缩小
        • 拖拽
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档