feat: 支持左键添加点,右键删除点
This commit is contained in:
parent
972028ab9d
commit
dc1670bb4c
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<div class="anno-img-box">
|
||||||
|
<div class="point-box">
|
||||||
|
<img class="anno-img" id="anno-img" @click="addPoint($event)" :src="`data:image/jpeg;base64,${src}`" @dragstart="$event.preventDefault()" @contextmenu="$event.preventDefault()">
|
||||||
|
<div v-for="point in points" :point="point" :key="`${point[0]}_${point[1]}`" :style="{
|
||||||
|
left: point[0]*100 + '%',
|
||||||
|
top: point[1]*100 + '%',
|
||||||
|
backgroundColor: point.color
|
||||||
|
}" class="point" @contextmenu="$event.preventDefault();delPoint(point)" @mouseover="overPoint($event, point)"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default ({
|
||||||
|
name: 'CVPoint',
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
points: [],
|
||||||
|
width: 0,
|
||||||
|
height: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
log (...args) {
|
||||||
|
console.log(args)
|
||||||
|
},
|
||||||
|
addPoint (ev) {
|
||||||
|
ev.preventDefault()
|
||||||
|
const tar = ev.target
|
||||||
|
const newPoint = [ev.offsetX / tar.offsetWidth, ev.offsetY / tar.offsetHeight]
|
||||||
|
console.log(newPoint)
|
||||||
|
this.points.push(newPoint)
|
||||||
|
console.log(this.points)
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
delPoint (point) {
|
||||||
|
const idx = this.points.indexOf(point)
|
||||||
|
console.log(point, this.points)
|
||||||
|
this.points.splice(idx, 1)
|
||||||
|
},
|
||||||
|
overPoint (ev, point) {
|
||||||
|
if (ev.which === 3) {
|
||||||
|
this.delPoint(point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// src: {
|
||||||
|
// handler (val) {
|
||||||
|
// const annoImg = document.getElementById('anno-img')
|
||||||
|
// annoImg.src = val
|
||||||
|
// console.log(annoImg.width)
|
||||||
|
// this.width = annoImg.width
|
||||||
|
// this.height = annoImg.height
|
||||||
|
// },
|
||||||
|
// deep: true
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.anno-img-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.anno-img {
|
||||||
|
width: 100%;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.point-box {
|
||||||
|
width: 300px;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
.point {
|
||||||
|
position: absolute;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #f00;
|
||||||
|
}
|
||||||
|
.point:hover {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -50,7 +50,7 @@
|
||||||
<template v-for="(w, i) in word.name">
|
<template v-for="(w, i) in word.name">
|
||||||
<line
|
<line
|
||||||
v-if="i === 0 || ((word.start%columnWordCount)+i) % columnWordCount === 0"
|
v-if="i === 0 || ((word.start%columnWordCount)+i) % columnWordCount === 0"
|
||||||
:key="`${word}${w}${i}`"
|
:key="`${word}${w}${i}`"
|
||||||
:x1="`${((word.start+i)%columnWordCount)*20 + (word.isSmall && i === 0 ? 2 : 0)}px`"
|
:x1="`${((word.start+i)%columnWordCount)*20 + (word.isSmall && i === 0 ? 2 : 0)}px`"
|
||||||
:y1="`${((word.start+i)/columnWordCount|0)*35 + (word.isSmall ? 0 : -2)}px`"
|
:y1="`${((word.start+i)/columnWordCount|0)*35 + (word.isSmall ? 0 : -2)}px`"
|
||||||
:x2="`${((Math.min(word.end-(word.start+i), columnWordCount, columnWordCount - (word.start+i)%columnWordCount))*20 - (word.isSmall && i === 0 ? 4 : 0)) + ((word.start+i)%columnWordCount)*20 + (word.isSmall && i === 0 ? 2 : 0)}px`"
|
:x2="`${((Math.min(word.end-(word.start+i), columnWordCount, columnWordCount - (word.start+i)%columnWordCount))*20 - (word.isSmall && i === 0 ? 4 : 0)) + ((word.start+i)%columnWordCount)*20 + (word.isSmall && i === 0 ? 2 : 0)}px`"
|
||||||
|
@ -62,37 +62,39 @@
|
||||||
</span>
|
</span>
|
||||||
<text x="201" y="10" fill="red">关系一</text>
|
<text x="201" y="10" fill="red">关系一</text>
|
||||||
</svg> -->
|
</svg> -->
|
||||||
<div class="word-rect-area">
|
<div v-if="projectType === '命名实体识别'">
|
||||||
<span class="rect" v-for="(word, idx) in nowNers" :key="idx">
|
<div class="word-rect-area">
|
||||||
<span v-for="(w, i) in word.name" :key="`${word}${w}${i}`">
|
<span class="rect" v-for="(word, idx) in nowNers" :key="idx">
|
||||||
<!-- <span class="ner-type"
|
<span v-for="(w, i) in word.name" :key="`${word}${w}${i}`">
|
||||||
v-if="i===0"
|
<!-- <span class="ner-type"
|
||||||
:style="{
|
v-if="i===0"
|
||||||
left: `${((word.start+i)%columnWordCount)*20}px`,
|
:style="{
|
||||||
top: `${((word.start+i)/columnWordCount|0)*35 - 14}px`,
|
left: `${((word.start+i)%columnWordCount)*20}px`,
|
||||||
}"
|
top: `${((word.start+i)/columnWordCount|0)*35 - 14}px`,
|
||||||
>{{word.type}}</span> -->
|
}"
|
||||||
<span class="ner-anchor"
|
>{{word.type}}</span> -->
|
||||||
v-if="i === 0 || ((word.start%columnWordCount)+i) % columnWordCount === 0"
|
<span class="ner-anchor"
|
||||||
:style="{
|
v-if="i === 0 || ((word.start%columnWordCount)+i) % columnWordCount === 0"
|
||||||
border: '1px solid #ccc',
|
:style="{
|
||||||
position: 'absolute',
|
border: '1px solid #ccc',
|
||||||
display: 'inline-block',
|
position: 'absolute',
|
||||||
left: `${((word.start+i)%columnWordCount)*20 + (word.isSmall && i === 0 ? 2 : 0)}px`,
|
display: 'inline-block',
|
||||||
top: `${((word.start+i)/columnWordCount|0)*35 + (word.isSmall ? 0 : -2)}px`,
|
left: `${((word.start+i)%columnWordCount)*20 + (word.isSmall && i === 0 ? 2 : 0)}px`,
|
||||||
width: `${(Math.min(word.end-(word.start+i), columnWordCount, columnWordCount - (word.start+i)%columnWordCount))*20 - (word.isSmall && i === 0 ? 4 : 0)}px`,
|
top: `${((word.start+i)/columnWordCount|0)*35 + (word.isSmall ? 0 : -2)}px`,
|
||||||
height: `${word.isSmall?18:22}px`,
|
width: `${(Math.min(word.end-(word.start+i), columnWordCount, columnWordCount - (word.start+i)%columnWordCount))*20 - (word.isSmall && i === 0 ? 4 : 0)}px`,
|
||||||
background: `${types[word.type]?types[word.type]['color']:'000000'}`,
|
height: `${word.isSmall?18:22}px`,
|
||||||
lineHeight: '25px',
|
background: `${types[word.type]?types[word.type]['color']:'000000'}`,
|
||||||
borderTopLeftRadius: `${(i===0)?6:0}px`,
|
lineHeight: '25px',
|
||||||
borderBottomLeftRadius: `${(i===0)?6:0}px`,
|
borderTopLeftRadius: `${(i===0)?6:0}px`,
|
||||||
borderLeft: `${i===0?1:0} solid #ccc`,
|
borderBottomLeftRadius: `${(i===0)?6:0}px`,
|
||||||
borderTopRightRadius: `${(i!==0 && word.name.length-i <= columnWordCount) || (i===0 && word.start%columnWordCount+word.name.length <= columnWordCount)?6:0}px`,
|
borderLeft: `${i===0?1:0} solid #ccc`,
|
||||||
borderBottomRightRadius: `${(i!==0 && word.name.length-i <= columnWordCount) || (i===0 && word.start%columnWordCount+word.name.length <= columnWordCount)?6:0}px`,
|
borderTopRightRadius: `${(i!==0 && word.name.length-i <= columnWordCount) || (i===0 && word.start%columnWordCount+word.name.length <= columnWordCount)?6:0}px`,
|
||||||
borderRight: `${(i!==0 && word.name.length-i <= columnWordCount) || (i===0 && word.start%columnWordCount+word.name.length < columnWordCount)?1:0} solid #ccc`
|
borderBottomRightRadius: `${(i!==0 && word.name.length-i <= columnWordCount) || (i===0 && word.start%columnWordCount+word.name.length <= columnWordCount)?6:0}px`,
|
||||||
}"></span>
|
borderRight: `${(i!==0 && word.name.length-i <= columnWordCount) || (i===0 && word.start%columnWordCount+word.name.length < columnWordCount)?1:0} solid #ccc`
|
||||||
|
}"></span>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="projectType === '命名实体识别'">
|
<div v-if="projectType === '命名实体识别'">
|
||||||
<span class="word" v-for="(word, idx) in nowText" :key="idx" :id="idx" @contextmenu="stopPrev" @mousedown="startSelect(idx, $event)" @touchstart="startSelect(idx, $event)" @mousemove="pointWord(idx)" @touchmove="pointWordByTouch($event)"
|
<span class="word" v-for="(word, idx) in nowText" :key="idx" :id="idx" @contextmenu="stopPrev" @mousedown="startSelect(idx, $event)" @touchstart="startSelect(idx, $event)" @mousemove="pointWord(idx)" @touchmove="pointWordByTouch($event)"
|
||||||
|
@ -106,9 +108,7 @@
|
||||||
<br v-if="word === '\n'" :key="idx"/>
|
<br v-if="word === '\n'" :key="idx"/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="projectType === '图片点标注'">
|
<CVPoint v-if="projectType === '图片点标注'" :src="nowText"></CVPoint>
|
||||||
<img :src="nowText" class="anno-img">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="page-btn-box">
|
<div class="page-btn-box">
|
||||||
<button class="page-btn" @click="changeIdx(-1, $event)" @mouseover="setFocus('page-up')" @mouseleave="setFocus('')">上一个 {{ fastTypeKey['page-up'] ? `【${fastTypeKey['page-up']}】` : '' }}</button>
|
<button class="page-btn" @click="changeIdx(-1, $event)" @mouseover="setFocus('page-up')" @mouseleave="setFocus('')">上一个 {{ fastTypeKey['page-up'] ? `【${fastTypeKey['page-up']}】` : '' }}</button>
|
||||||
|
@ -134,6 +134,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { getColor } from '../../js/color.js'
|
import { getColor } from '../../js/color.js'
|
||||||
import { saveAsFile } from '../../js/utils.js'
|
import { saveAsFile } from '../../js/utils.js'
|
||||||
|
import CVPoint from '@/components/CV/point.vue'
|
||||||
|
|
||||||
// 是否是单机版
|
// 是否是单机版
|
||||||
const isLocal = false
|
const isLocal = false
|
||||||
|
@ -188,6 +189,9 @@ function updateType2Server (projectName, typeList, types) {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NER',
|
name: 'NER',
|
||||||
|
components: {
|
||||||
|
CVPoint
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
configCanCtlType: isLocal, // 是否支持实体类型的调整
|
configCanCtlType: isLocal, // 是否支持实体类型的调整
|
||||||
|
@ -340,9 +344,6 @@ export default {
|
||||||
that.$set(that.nersCache, that.nowFile, [...that.ners])
|
that.$set(that.nersCache, that.nowFile, [...that.ners])
|
||||||
that.flushWordsType()
|
that.flushWordsType()
|
||||||
}
|
}
|
||||||
if (info.fileContent[0] !== 'd') {
|
|
||||||
info.fileContent = 'data:image/jpeg;base64,' + info.fileContent
|
|
||||||
}
|
|
||||||
// 更新文件的文本信息
|
// 更新文件的文本信息
|
||||||
that.$set(that.textDic, newFile, info.fileContent)
|
that.$set(that.textDic, newFile, info.fileContent)
|
||||||
that.nowText = that.textDic[newFile]
|
that.nowText = that.textDic[newFile]
|
||||||
|
@ -1054,9 +1055,6 @@ export default {
|
||||||
top: -9px;
|
top: -9px;
|
||||||
right: -9px;
|
right: -9px;
|
||||||
}
|
}
|
||||||
.anno-img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
.out-title {
|
.out-title {
|
||||||
text-align: right !important;
|
text-align: right !important;
|
||||||
|
|
Loading…
Reference in New Issue