<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>
canvas 做ocr 标注数据坐标
最新推荐文章于 2025-04-26 13:37:37 发布