本篇文章給大家分享的是有關(guān)vue實(shí)現(xiàn)一個(gè)矩形標(biāo)記區(qū)域的方法,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

代碼實(shí)現(xiàn)
<template>
<div class="rectangle-marker">
<div class="mark-wrap">
<img ref="backImg" :src="imgUrl" class="img-responsive" alt="響應(yīng)式圖像" @load="onload">
<div class="draw-rect" :class="{ 'no-event': disabled }" @mousemove="mouseMove"
@mousedown="mouseDown" @mouseup="mouseUp">
<div ref="box" v-if="boxVisible" :id="boxId" class="box"
:>
<div id="upleftbtn" class="upleftbtn" @mousedown="onUpleftbtn"></div>
<div id="uprightbtn" class="uprightbtn" @mousedown="onUpRightbtn"></div>
<div id="downleftbtn" class="downleftbtn" @mousedown="onDownleftbtn"></div>
<div id="downrightbtn" class="downrightbtn" @mousedown="onDownRightbtn"></div>
</div>
</div>
<transition name="fade">
<div v-if="showBtns && !markFlag" class="act-btns" @mouseleave="mouseLeave">
<button @click="mark">mark</button>
<button @click="reset">reset</button>
</div>
</transition>
</div>
</div>
</template>
<script>
export default {
name: 'rectangleMarker',
data() {
return {
imgW: 0,
imgH: 0,
showBtns: true,
markFlag: false,
// 鼠標(biāo)事件屬性
dragging: false,
startX: undefined,
startY: undefined,
diffX: undefined,
diffY: undefined,
obj: null, //當(dāng)前操作對象
box: null, //要處理的對象
backImgRect: null,
boxId: '',
boxW: 0,
boxH: 0,
boxL: 0,
boxT: 0,
boxVisible: false
}
},
props: {
imgUrl: {
type: String,
required: true,
default: ''
},
disabled: {
type: Boolean,
default: false
},
value: {
type: Array,
default: function () {
return []
}
}
},
methods: {
onload() {
let rect = this.$refs.backImg.getBoundingClientRect()
this.backImgRect = {
height: rect.height,
width: rect.width
}
// console.log("initConfig -> this.backImgRect", this.backImgRect)
if (this.value === '' || this.value === undefined || this.value === null || (Array.isArray(this.value) && this.value.length === 0)) {
return
}
this.initData(this.value)
},
mouseLeave() {
this.showBtns = false
},
mark() {
this.markFlag = true
},
reset() {
this.boxVisible = false
this.boxId = ''
this.boxH = 0
this.boxW = 0
this.boxL = 0
this.boxT = 0
},
initData(data) {
if (data === '' || data === undefined || data === null || (Array.isArray(data) && data.length === 0)) {
return
}
this.boxId = 'changeBox'
this.boxL = data[0][0] * this.backImgRect.width
this.boxT = data[0][1] * this.backImgRect.height
this.boxH = (data[3][1] - data[0][1]) * this.backImgRect.height
this.boxW = (data[1][0] - data[0][0]) * this.backImgRect.width
this.boxVisible = true
},
mouseDown(e) {
if (!this.markFlag && !this.boxVisible) {
return
}
this.startX = e.offsetX;
this.startY = e.offsetY;
// 如果鼠標(biāo)在 box 上被按下
if (e.target.className.match(/box/)) {
// 允許拖動(dòng)
this.dragging = true;
// 設(shè)置當(dāng)前 box 的 id 為 movingBox
if (this.boxId !== 'movingBox') {
this.boxId = 'movingBox'
}
// 計(jì)算坐標(biāo)差值
this.diffX = this.startX
this.diffY = this.startY
} else {
if (this.boxId === 'changeBox') {
return
}
this.boxId = 'activeBox'
this.boxT = this.startY
this.boxL = this.startX
this.boxVisible = true
}
},
mouseMove(e) {
if (!this.markFlag && !this.boxVisible) {
if (!this.backImgRect) {
return
}
let toRight = this.backImgRect.width - e.offsetX
let toTop = e.offsetY
if (toRight <= 100 && toTop <= 40) {
this.showBtns = true
}
return
}
let toRight = this.backImgRect.width - e.offsetX
let toTop = e.offsetY
if (toRight <= 100 && toTop <= 40) {
this.showBtns = true
return
}
// 更新 box 尺寸
if (this.boxId === 'activeBox') {
this.boxW = e.offsetX - this.startX
this.boxH = e.offsetY - this.startY
}
// 移動(dòng),更新 box 坐標(biāo)
if (this.boxId === 'movingBox' && this.dragging) {
let realTop = (e.offsetY + e.target.offsetTop - this.diffY) > 0 ? (e.offsetY + e.target.offsetTop -
this.diffY) : 0
let realLeft = (e.offsetX + e.target.offsetLeft - this.diffX) > 0 ? (e.offsetX + e.target.offsetLeft -
this.diffX) : 0
let maxTop = this.backImgRect.height - this.$refs.box.offsetHeight
let maxLeft = this.backImgRect.width - this.$refs.box.offsetWidth
realTop = realTop >= maxTop ? maxTop : realTop
realLeft = realLeft >= maxLeft ? maxLeft : realLeft
this.boxT = realTop;
this.boxL = realLeft;
}
if (this.obj) {
e = e || window.event;
var location = {
x: e.x || e.offsetX,
y: e.y || e.offsetY
}
switch (this.obj.operateType) {
case "nw":
this.move('n', location, this.$refs.box);
this.move('w', location, this.$refs.box);
break;
case "ne":
this.move('n', location, this.$refs.box);
this.move('e', location, this.$refs.box);
break;
case "sw":
this.move('s', location, this.$refs.box);
this.move('w', location, this.$refs.box);
break;
case "se":
this.move('s', location, this.$refs.box);
this.move('e', location, this.$refs.box);
break;
case "move":
this.move('move', location, this.box);
break;
}
}
},
mouseUp() {
if (!this.markFlag && !this.boxVisible) {
return
}
// 禁止拖動(dòng)
this.dragging = false;
if (this.boxId === 'activeBox') {
if (this.$refs.box) {
this.boxId = 'changeBox'
if (this.$refs.box.offsetWidth < 3 || this.$refs.box.offsetHeight < 3) {
this.boxVisible = false
this.boxId = ''
}
}
} else {
if (this.$refs.box && this.boxId === 'movingBox') {
this.boxId = 'changeBox'
if (this.$refs.box.offsetWidth < 3 || this.$refs.box.offsetHeight < 3) {
this.boxVisible = false
this.boxId = ''
}
}
}
if (this.boxVisible) {
this.getHotData()
document.body.style.cursor = "auto";
this.obj = null;
this.markFlag = false
} else {
this.markFlag = true
}
},
getHotData() {
let target = this.$refs.box
if (target) {
let {
offsetTop,
offsetLeft
} = target
let {
width: WIDTH,
height: HEIGHT
} = this.backImgRect
let {
width,
height
} = target.getBoundingClientRect()
// 矩形區(qū)域 角點(diǎn)位置(百分比)
let data = [
[this.toFixed6(offsetLeft, WIDTH), this.toFixed6(offsetTop, HEIGHT)],
[this.toFixed6(offsetLeft + width, WIDTH), this.toFixed6(offsetTop, HEIGHT)],
[this.toFixed6(offsetLeft + width, WIDTH), this.toFixed6(offsetTop + height, HEIGHT)],
[this.toFixed6(offsetLeft, WIDTH), this.toFixed6(offsetTop + height, HEIGHT)]
]
// 矩形中點(diǎn)
let centerPoint = [
this.toFixed6(offsetLeft + 0.5 * width, WIDTH),
this.toFixed6(offsetTop + 0.5 * height, HEIGHT)
]
let hotData = {
data,
centerPoint
}
console.log("getHotData -> hotData", hotData)
console.log(JSON.stringify(hotData));
}
},
toFixed6(v1, v2) {
return (v1 / v2).toFixed(6)
},
move(type, location, tarobj) {
switch (type) {
case 'n': {
let add_length = this.clickY - location.y;
this.clickY = location.y;
let length = parseInt(tarobj.style.height) + add_length;
tarobj.style.height = length + "px";
let realTop = this.clickY > 0 ? this.clickY : 0
let maxTop = this.backImgRect.height - parseInt(tarobj.style.height)
realTop = realTop >= maxTop ? maxTop : realTop
tarobj.style.top = realTop + "px";
break;
}
case 's': {
let add_length = this.clickY - location.y;
this.clickY = location.y;
let length = parseInt(tarobj.style.height) - add_length;
let maxHeight = this.backImgRect.height - parseInt(tarobj.style.top)
let realHeight = length > maxHeight ? maxHeight : length
tarobj.style.height = realHeight + "px";
break;
}
case 'w': {
var add_length = this.clickX - location.x;
this.clickX = location.x;
let length = parseInt(tarobj.style.width) + add_length;
tarobj.style.width = length + "px";
let realLeft = this.clickX > 0 ? this.clickX : 0
let maxLeft = this.backImgRect.width - parseInt(tarobj.style.width)
realLeft = realLeft >= maxLeft ? maxLeft : realLeft
tarobj.style.left = realLeft + "px";
break;
}
case 'e': {
let add_length = this.clickX - location.x;
this.clickX = location.x;
let length = parseInt(tarobj.style.width) - add_length;
let maxWidth = this.backImgRect.width - parseInt(tarobj.style.left)
let realWidth = length > maxWidth ? maxWidth : length
tarobj.style.width = realWidth + "px";
break;
}
}
},
onUpleftbtn(e) {
e.stopPropagation();
this.onDragDown(e, "nw");
},
onUpRightbtn(e) {
e.stopPropagation();
this.onDragDown(e, "ne");
},
onDownleftbtn(e) {
e.stopPropagation();
this.onDragDown(e, "sw");
},
onDownRightbtn(e) {
e.stopPropagation();
this.onDragDown(e, "se");
},
onDragDown(e, type) {
e = e || window.event;
this.clickX = e.x || e.offsetX;
this.clickY = e.y || e.offsetY;
this.obj = window;
this.obj.operateType = type;
this.box = this.$refs.box;
return false;
}
},
}
</script>
<style lang="less" scoped>
.rectangle-marker {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
.mark-wrap {
position: relative;
.img-responsive {
display: inline-block;
max-width: 100%;
max-height: 100%;
}
.draw-rect {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
z-index: 99;
user-select: none;
&.no-event {
pointer-events: none;
}
}
}
.act-box {
margin-top: 10px;
display: flex;
}
.act-btns {
position: absolute;
right: 0;
top: 0;
z-index: 199;
padding: 0 10px;
height: 40px;
width: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.fade-enter-active {
animation: hide-and-show .5s;
}
.fade-leave-active {
animation: hide-and-show .5s reverse;
}
@keyframes hide-and-show {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
}
</style>
<style lang="less">
.rectangle-marker {
.box {
position: absolute;
width: 0px;
height: 0px;
opacity: 0.5;
z-index: 149;
cursor: move;
border: 1px solid #f00;
.upleftbtn,
.uprightbtn,
.downleftbtn,
.downrightbtn {
width: 10px;
height: 10px;
border: 1px solid steelblue;
position: absolute;
z-index: 5;
background: whitesmoke;
border-radius: 10px;
}
.upleftbtn {
top: -5px;
left: -5px;
cursor: nw-resize;
}
.uprightbtn {
top: -5px;
right: -5px;
cursor: ne-resize;
}
.downleftbtn {
left: -5px;
bottom: -5px;
cursor: sw-resize;
}
.downrightbtn {
right: -5px;
bottom: -5px;
cursor: se-resize;
}
}
}
</style>
分享名稱:vue實(shí)現(xiàn)一個(gè)矩形標(biāo)記區(qū)域的方法-創(chuàng)新互聯(lián)
URL分享:http://www.chinadenli.net/article0/deejio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、網(wǎng)站設(shè)計(jì)、企業(yè)網(wǎng)站制作、面包屑導(dǎo)航、域名注冊、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容