canvas 做ocr 标注数据坐标

<template>
  <el-form ref="form" :rules="rules" :model="form" label-width="80px" >
    <el-row>
      <el-col :span="2" :offset="1">
        <el-form-item label="扫描件" prop="certificateUrl">
          <el-upload
            :disabled="disabled"
            class="avatar-uploader"
            action="#"
            :show-file-list="false"
            :on-change="handleAvatarChange"
            :on-success="handleAvatarSuccess"
            :before-upload="beforeAvatarUpload"
            :with-credentials="true"
          >
            <img v-if="form.certificateUrl" :src="form.certificateUrl" class="avatar">
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
          </el-upload>
        </el-form-item>
      </el-col>
      <el-col :span="2" :offset="1">

      </el-col>

    </el-row>
    <el-row >
      <el-col :span="24" >
        <el-form-item label="" prop="content">
          <div ref="divCanvas" class="divCanvas">
            <!--dragCircle-->
            <canvas ref="myCanvas"    style="background-color: #FFFFFF;" @contextmenu="canvaContextmenu"
                    @mousedown="canvasClick" @mouseup="stopDragging" @mouseout="stopDragging" @mousemove="mousemove" @dblclick="doubleClick">
              您的浏览器不支持 HTML5 canvas 标签。
            </canvas>
            <el-menu ref="canvaRightMenu" class="el-menu-hidden" @select="handleRightMenuSelect">
              <el-menu-item   v-for="item in comboxData" :index="item.code" v-if="item.disabled">
                <span slot="title">{{item.name}}</span>
              </el-menu-item>
              <el-menu-item index="clearAllTag">
                <span slot="title">清除所有标签</span>
              </el-menu-item>
            </el-menu>
          </div>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>

<script>

export default {
  name: 'certificateEdit',
  data() {
    return {
      canvasWidth: 1000 ,//1240,// 595 ,    //根据图片大小自适应canvas宽
      canvasHeight: 1500,//1754,//842 ,    //根据图片大小自适应canvas高
      scaleX : 1,
      scaleY: 1,
      isoriginal: false , //是否原型
      startX: '',  //画画开始的X坐标
      startY: '',  //画画开始的Y坐标
      endX: '',    //画画结束的X坐标
      endY: '',    //画画结束的Y坐标
      distanceX: '' , //鼠标X坐标到startX距离
      distanceY: '' ,//鼠标Y坐标到startY距离
      customcxt: '',      // cxt
      canvas: '',
      form: {
        certificateUrl: "",
        coordinates: []
      },
      rules: {
        certificateUrl: [
          { required: true, message: '请上传图片', trigger: 'blur' }
        ],
      },
      comboxData: [{ code: 'name', name:'名称', disabled: true },{ code: 'createTimeStart', name:'开始时间', disabled: true},{ code: 'createTimeEnd', name:'结束时间', disabled: true}],
      inParams: {},
      disabled: false,
      canvasX: 0, //右建菜单X坐标
      canvasY: 0,
      isDragging:false,         //是否移动矩形
      isMouseDownCanvas: false, //鼠标是否按下画矩形
      isMouseDownInCanvas: false ,
      previousSelectedCircle:null
    }
  },
  created() {
  },
  watch:{
    'form.certificateUrl':{
      handler(newValue,oldValue){
        if(newValue)
        {
          this.initCanvas();
        }
      },
      deep:true
    }
  },
  methods: {
    findXyRange(e){
      let canvas = this.$refs.myCanvas;
      // 取得画布上被单击的点
      var clickX = e.offsetX - canvas.offsetLeft;
      var clickY = e.offsetY - canvas.offsetTop;
      let datas = this.form.coordinates;
      const idx = datas.findIndex(circle=>{
        const w = circle.w ? circle.w : 0
        const h = circle.h ? circle.h : 0
        // 判断这个点是否在中
        let xz = clickX >= circle.xaxis && clickX <= circle.xaxis + w;
        let yz = clickY >= circle.yaxis - 20 && clickY <= circle.yaxis + h;
        if (xz && yz) {
          return true
        }
      })
      return idx
    },
    doubleClick(e){
      const  idx = this.findXyRange(e)

      if(idx >-1){
        const data = this.form.coordinates[idx]
        let value = this.comboxData.find(t => t.code === data.labelCode);
        if(value){
          value.disabled = true
        }
         //删除元素
        this.form.coordinates.splice(idx,1)
        this.initCanvas();
      }


    },
    handleAvatarChange(file, fileList) {
      //图片改变
      this.form.certificateUrl = URL.createObjectURL(file.raw);
    },
    handleAvatarSuccess(res, file) {
      //上传完成
      // if(res && res.code==200)
      //{
      //      this.form.certificateUrl = res.result.url;
      //}
    },
    beforeAvatarUpload(file) {
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg';
      const isLt2M = file.size / 1024 / 1024 < 2;

      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG,png 格式!');
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!');
      }
      return isJPG && isLt2M;
    },
    contentBlur() {
      //内容输入完成初始化canvas
      this.initCanvas();
    },
    canvaContextmenu(event) {
      //canva右键列表
      var event = event || window.event;
      this.canvasX = event.offsetX+10;
      this.canvasY = event.offsetY+20;
      this.$refs.canvaRightMenu.$el.style.display = "block";
      this.$refs.canvaRightMenu.$el.style.position = "absolute";
      this.$refs.canvaRightMenu.$el.style.border = "solid 1px #dcdfe6";
      this.$refs.canvaRightMenu.$el.style.left =event.offsetX + "px";
      this.$refs.canvaRightMenu.$el.style.top = event.offsetY+ "px";
      event.preventDefault();
    },
    handleRightMenuSelect(index, indexPath) {
      //右键菜单选择标签
      if (index === 'clearAllTag') {
        this.form.coordinates = [];
        this.comboxData.some(item=>{
          item.disabled = true;
        })
      } else {
        let item = this.form.coordinates.find(t => t.labelCode === index);
        if (!item) {
          let value = this.comboxData.find(t => t.code === index);
          let  dataIndex=  this.form.coordinates.findIndex(circle =>{
            let xz= this.canvasX >= circle.xaxis-10 && this.canvasX <= circle.xaxis+circle.w +10;
            let yz= this.canvasY >= circle.yaxis-20 && this.canvasY <= circle.yaxis+circle.h +20;
            console.log("canvasX:" +this.canvasX + "  "+(circle.xaxis-10)+" "+(circle.xaxis+circle.w +10))
            console.log("canvasY:" +this.canvasY + "  "+(circle.yaxis-20) +" "+ (circle.yaxis+circle.h +20))
            console.log(xz +'  '+yz)
            if( xz && yz)
            {
              return true
            }
          })
          console.log(this.form.coordinates.length + "  index:"+dataIndex)
        if(dataIndex> -1){
          let obj = this.form.coordinates[dataIndex]
          obj.labelCode =  value.code
          obj.labelName = value.name
          value.disabled = false;
        }else{
          this.$message.info("请先标注识别框!")

        }

        }
      }
      this.$refs.canvaRightMenu.$el.style.display = "none";
      this.initCanvas();
    },
    initCanvas() {
      //初始化canvas
      console.log("initCanvas");
      let vue = this;
      if(!vue.form.certificateUrl)
      {
        return;
      }
      vue.$refs.divCanvas.style.display = "block";
      let canvas = vue.$refs.myCanvas;
      vue.canvas = canvas
      let ctx = canvas.getContext('2d');
      this.customcxt  = ctx
      let img = new Image();
      img.src = vue.form.certificateUrl;
      //图片加载完成添加图片及文字
      img.onload = function() {
        if(vue.isoriginal )
        {
          console.log("=============================")
           canvas.width = img.width;
           canvas.height = img.height
        }else{
          //按等比放缩
          let WrH = img.width / img.height;             //图片宽高比
          let RWrH = vue.canvasWidth / vue.canvasHeight;    //放置图片DIV的宽高比
          let aa = 1;
          // 根据宽高比大小判断确定自适应的宽和高
          if (RWrH > WrH) {
            aa = vue.canvasHeight / img.height;
            vue.canvasWidth = img.width * aa;
          } else {
            aa = vue.canvasWidth / img.width;
            vue.canvasHeight = img.height * aa;
          }
         //重新设置画板大小
          canvas.width = vue.canvasWidth;
          canvas.height = vue.canvasHeight
        }
         vue.scaleX = canvas.width / img.width;
         vue.scaleY = canvas.height / img.height;

        //清除canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        //添加背景 
        ctx.drawImage(img, 0, 0,canvas.width, canvas.height);

        let font = "11px caption ";
        ctx.lineWidth = "2";  //矩形框宽度
        ctx.font = font;
        //添加标签
       vue.form.coordinates.forEach(item => {
         if(item.w != 0 &&item.h !=0 ){
           //ctx.strokeStyle = "#00ff00"; //矩形框颜色
           ctx.strokeStyle = "red";
           ctx.strokeRect(item.xaxis, item.yaxis, item.w, item.h) //绘制矩形
           //白颜色填充画绿色边框
            /* ctx.fillStyle ='#00ff00';
             const  b = 1
             ctx.fillRect((item.xaxis-b),item.yaxis-b,item.w+(b* 2),item.h+(b* 2))
             ctx.fillStyle='white'
             ctx.fillRect(item.xaxis, item.yaxis, item.w, item.h)*/
         }

          if(item.labelName != ''){
            ctx.fillStyle = 'red'
            if(!item.w){
              //这个情况不存在,在右键菜单判断,
              ctx.fillText('{' + item.labelName + '}',item.xaxis   , item.yaxis);
            }else{
              let textWidth = ctx.measureText('{'+item.labelName+"}").width;
              let textHeight =  6//ctx.measureText("高").width;
              //转整型,居中
             // let x = item.xaxis + Math.floor((item.w - textWidth)/2)
             // let y =  item.yaxis +Math.floor( (item.h -textHeight ) /2) + textHeight
              //居左上
            //  let x = item.xaxis  + 1
             // let y = item.yaxis + textHeight +1
              //居右下 textHeight =  6
              let x = item.xaxis + Math.floor((item.w - textWidth)) -2
              let y =  item.yaxis +Math.floor( (item.h -textHeight ) )  -2

              ctx.clearRect(x,y,textWidth,textHeight)
              ctx.fillText('{' + item.labelName + '}', x  , y);
            }
          }


        })
      }
    },

findBreakPoint(text, width, context) {
      //寻找切换断点
      let min = 0;
      let max = text.length - 1;

      while (min <= max) {
        let middle = Math.floor((min + max) / 2);
        let middleWidth = context.measureText(text.substr(0, middle)).width;
        let oneCharWiderThanMiddleWidth = context.measureText(text.substr(0, middle + 1)).width;
        if (middleWidth <= width && oneCharWiderThanMiddleWidth > width) {
          return middle;
        }
        if (middleWidth < width) {
          min = middle + 1;
        } else {
          max = middle - 1;
        }
      }

      return -1;
    },
    breakLinesForCanvas(context, text, width, font) {
      //内容换行
      let result = [];
      let breakPoint = 0;
      if (font) {
        context.font = font;
      }
      while ((breakPoint = this.findBreakPoint(text, width, context)) !== -1) {
        result.push(text.substr(0, breakPoint));
        text = text.substr(breakPoint);
      }
      if (text) {
        result.push(text);
      }
      return result;
    },
    canvasClick(e) {
      let canvas = this.$refs.myCanvas;
      // 取得画布上被单击的点
      var clickX = e.offsetX - canvas.offsetLeft;
      var clickY = e.offsetY - canvas.offsetTop;

      this.$refs.canvaRightMenu.$el.style.display = "none";
      // 查找被单击点在坐标数据范围内
      let datas = this.form.coordinates;
      for (var i = 0; i < datas.length; i++) {
        //处理datas[i]
        //var 指针类型
        var circle = datas[i];
        const  w = circle.w ?circle.w:0
        const  h = circle.h ?circle.h:0
        // 判断这个点是否在中
        let xz= clickX >= circle.xaxis && clickX <= circle.xaxis+ w;
        let yz= clickY >= circle.yaxis-20 && clickY <= circle.yaxis+h;
        if (xz && yz) {
          // 清除之前选择的
          if (this.previousSelectedCircle != null) this.previousSelectedCircle = null;
          //通过 this.form.coordinates来更新data[i]
          this.previousSelectedCircle = circle;
          this.distanceX = clickX - circle.xaxis
          this.distanceY = clickY - circle.yaxis ;
          // 使允许拖拽
          this.isDragging = true;
          //更新显示
           this.initCanvas();
          //停止搜索
          return;
        }
      }
      if(!this.isDragging ){
        //设置为画矩形
        this.isMouseDownCanvas = true;
        //新加
        this.startX = clickX;
        this.startY = clickY;

      }


    },
    stopDragging() {
      console.log("this.isMouseDownInCanvas:"+this.isMouseDownInCanvas)
      if(this.isMouseDownInCanvas){
        this.isMouseDownInCanvas = false;
        let wwidth = this.endX - this.startX;
        let wheigth = this.endY - this.startY;
        this.form.coordinates.push({
          labelCode: '',
          labelName: '',
          xaxis: this.startX,
          yaxis: this.startY,
          w: wwidth,
          h: wheigth,
          scaleX: this.scaleX,
          scaleY: this.scaleY
        });

        this.initCanvas();
      }
      this.isMouseDownCanvas = false;
      console.log('stopDragging');
      this.isDragging = false;
    },
    mousemove(e){
      let canvas = this.$refs.myCanvas;
      var x = e.offsetX  - canvas.offsetLeft;
      var y = e.offsetY -  canvas.offsetTop;
       if (this.isDragging) {
        this.previousSelectedCircle.xaxis = x -this.distanceX ;
        this.previousSelectedCircle.yaxis = y - this.distanceY;
        // 更新画布
        this.initCanvas();
      }else{
        //新加
      if (this.isMouseDownCanvas) { // 开始画矩形
        let wwidth = x - this.startX;
        let wheigth = y - this.startY;
        if( wwidth >0 && wheigth>0) {
          let ctx = canvas.getContext('2d');
          let owidth = this.endX - this.startX;
          let oheigth = this.endY - this.startY;
          ctx.strokeStyle = "red" //矩形框颜色   "#00ff00"
          ctx.lineWidth = "2";  //矩形框宽度
          ctx.clearRect(this.startX- ctx.lineWidth , this.startY-ctx.lineWidth , owidth+ctx.lineWidth * 2 , oheigth+ctx.lineWidth*2)
          ctx.strokeRect(this.startX, this.startY, wwidth, wheigth) //绘制矩形
           this.isMouseDownInCanvas = true  //正在画矩形
        }else{
            this.isMouseDownInCanvas = false //开始画,但未画
        }
        this.endX = x;
        this.endY = y;
        }
      }
    },
  }
}
</script>

<style scoped>
  .avatar-uploader >>> .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    border-radius: 0%;
    float: left;
  }
  .avatar-uploader >>> .el-upload:hover {
    border-color: #409EFF;
  }
  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 60px;
    height: 60px;
    line-height: 60px;
    text-align: center;
  }
  .avatar {
    width: 60px;
    height: 60px;
    display: block;
  }
  .el-textarea >>> .el-textarea__inner{
    height: 60px;
  }
  .el-dialog__wrapper >>> .el-dialog{
    width: 1200px;
    height: 880px;
  }
  .divCanvas {

   /* width: 100%;
   min-height: 300px;
    max-height: 600px;*/
    width: 1460px;
    height:540px;
    overflow: auto;
    margin-bottom: 10px;
    border: solid 1px #f0f2f5;
    float: left;
    position: relative;
    display: none;
  }
  .el-tree-node {
    font-size: 14px;
    margin-right: 20px;
  }
  .el-menu-hidden {display: none;}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值