封装v-drag
This commit is contained in:
parent
437738b211
commit
557f557857
@ -44,6 +44,7 @@ import VueDOMPurifyHTML from 'vue-dompurify-html' // 解决v-html 的安全隐
|
|||||||
import VueDragResizeRotate from '@gausszhou/vue3-drag-resize-rotate'
|
import VueDragResizeRotate from '@gausszhou/vue3-drag-resize-rotate'
|
||||||
import '@gausszhou/vue3-drag-resize-rotate/lib/bundle.esm.css'
|
import '@gausszhou/vue3-drag-resize-rotate/lib/bundle.esm.css'
|
||||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||||
|
import { vDrag } from './utils/drag';
|
||||||
// 创建实例
|
// 创建实例
|
||||||
const setupAll = async () => {
|
const setupAll = async () => {
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
@ -67,7 +68,8 @@ const setupAll = async () => {
|
|||||||
setupMountedFocus(app)
|
setupMountedFocus(app)
|
||||||
|
|
||||||
await router.isReady()
|
await router.isReady()
|
||||||
|
// 注册全局指令
|
||||||
|
app.directive('drag', vDrag);
|
||||||
app.use(VueDOMPurifyHTML)
|
app.use(VueDOMPurifyHTML)
|
||||||
app.use(VueDragResizeRotate)
|
app.use(VueDragResizeRotate)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
31
src/utils/drag.ts
Normal file
31
src/utils/drag.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// directives.js
|
||||||
|
export const vDrag = {
|
||||||
|
mounted(el) {
|
||||||
|
el.style.position = 'absolute';
|
||||||
|
|
||||||
|
let startX, startY, initialMouseX, initialMouseY;
|
||||||
|
|
||||||
|
const mousemove = (e) => {
|
||||||
|
const dx = e.clientX - initialMouseX;
|
||||||
|
const dy = e.clientY - initialMouseY;
|
||||||
|
el.style.top = `${startY + dy}px`;
|
||||||
|
el.style.left = `${startX + dx}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mouseup = () => {
|
||||||
|
document.removeEventListener('mousemove', mousemove);
|
||||||
|
document.removeEventListener('mouseup', mouseup);
|
||||||
|
};
|
||||||
|
|
||||||
|
el.addEventListener('mousedown', (e) => {
|
||||||
|
startX = el.offsetLeft;
|
||||||
|
startY = el.offsetTop;
|
||||||
|
initialMouseX = e.clientX;
|
||||||
|
initialMouseY = e.clientY;
|
||||||
|
document.addEventListener('mousemove', mousemove);
|
||||||
|
document.addEventListener('mouseup', mouseup);
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="affix-container">
|
<div class="affix-container" :style="{ height: heightVal + 'px' }">
|
||||||
<el-affix target=".affix-container" :offset="80">
|
<el-affix target=".affix-container" :offset="80">
|
||||||
<div class="affix-container-top">
|
<div class="affix-container-top">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
@ -28,14 +28,26 @@
|
|||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</el-affix>
|
</el-affix>
|
||||||
<div class="indexpage-container" v-if="imgUrl">
|
<div class="indexpage-container" v-if="imgUrl" v-drag>
|
||||||
<div class="indexpage-container-box">
|
<div class="indexpage-container-box">
|
||||||
<img :src="imgUrl" alt="" class="indexpage-container-box-img" />
|
<img :src="imgUrl" alt="" class="indexpage-container-box-img" />
|
||||||
|
|
||||||
<div class="indexpage-container-box-point">
|
<div class="indexpage-container-box-point">
|
||||||
<div class="line-box" v-for="(item, index) in lineList" :key="index" :style="{ left: item.left * radio + 'px', top: item.top * radio + 'px', width: item.distance * radio + 'px', height: item.height * radio + 'px', transform: 'rotate(' + item.angle + 'deg)', backgroundColor: item.color ,transformOrigin: 'left top'}">
|
<div
|
||||||
|
class="line-box"
|
||||||
</div>
|
v-for="(item, index) in lineList"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
left: item.left * radio + 'px',
|
||||||
|
top: item.top * radio + 'px',
|
||||||
|
width: item.distance * radio + 'px',
|
||||||
|
height: item.height * radio + 'px',
|
||||||
|
transform: 'rotate(' + item.angle + 'deg)',
|
||||||
|
backgroundColor: item.color,
|
||||||
|
transformOrigin: 'left top'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="indexpage-container-box-point-item"
|
class="indexpage-container-box-point-item"
|
||||||
v-for="(item, index) in pointList"
|
v-for="(item, index) in pointList"
|
||||||
@ -51,38 +63,48 @@
|
|||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div v-if="item.type == 2" style="width: 100%; height: 100%">
|
<div v-if="item.type == 2" style="width: 100%; height: 100%">
|
||||||
<el-popover
|
<el-popover placement="top-start" trigger="hover" width="auto">
|
||||||
placement="top-start"
|
|
||||||
trigger="hover"
|
|
||||||
width="auto"
|
|
||||||
>
|
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<img :src="item.imgUrl" alt="" style="width: 100%; height: 100%" @dblclick="storeClick(item)"/>
|
<img
|
||||||
|
:src="item.imgUrl"
|
||||||
|
alt=""
|
||||||
|
style="width: 100%; height: 100%"
|
||||||
|
@dblclick="storeClick(item)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div class="indexpage-container-box-point-item-inner-popover">
|
<div class="indexpage-container-box-point-item-inner-popover">
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
|
<div
|
||||||
|
class="indexpage-container-box-point-item-inner-popover-item"
|
||||||
|
style="margin-bottom: 8px"
|
||||||
|
>
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-name">
|
<div class="indexpage-container-box-point-item-inner-popover-name">
|
||||||
库位名:
|
库位名:
|
||||||
|
</div>
|
||||||
|
<div class="indexpage-container-box-point-item-inner-popover-value">
|
||||||
|
{{ item.showData.locationNo || '' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-value">
|
<div
|
||||||
{{ item.showData.locationNo || '' }}
|
class="indexpage-container-box-point-item-inner-popover-item"
|
||||||
</div>
|
style="margin-bottom: 8px"
|
||||||
</div>
|
>
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
|
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-name">
|
<div class="indexpage-container-box-point-item-inner-popover-name">
|
||||||
所属线库:
|
所属线库:
|
||||||
|
</div>
|
||||||
|
<div class="indexpage-container-box-point-item-inner-popover-value">
|
||||||
|
{{ item.showData.laneName || '' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-value">
|
<div
|
||||||
{{ item.showData.laneName || '' }}
|
class="indexpage-container-box-point-item-inner-popover-item"
|
||||||
</div>
|
style="margin-bottom: 8px"
|
||||||
</div>
|
>
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
|
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-name">
|
<div class="indexpage-container-box-point-item-inner-popover-name">
|
||||||
所属区域:
|
所属区域:
|
||||||
</div>
|
</div>
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-value">
|
<div class="indexpage-container-box-point-item-inner-popover-value">
|
||||||
{{ item.showData.areaName || '' }}
|
{{ item.showData.areaName || '' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
|
<!-- <div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-name">
|
<div class="indexpage-container-box-point-item-inner-popover-name">
|
||||||
@ -160,7 +182,7 @@ const getPositionMapListFun = async (positionMapId) => {
|
|||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
// console.log(JSON.parse(item.dataJson))
|
// console.log(JSON.parse(item.dataJson))
|
||||||
item.formattedData = item.dataJson ?JSON.parse(item.dataJson):''
|
item.formattedData = item.dataJson ? JSON.parse(item.dataJson) : ''
|
||||||
item.showData = item.dataJson ? JSON.parse(item.dataJson)[0] : null
|
item.showData = item.dataJson ? JSON.parse(item.dataJson)[0] : null
|
||||||
item.imgUrl = formatteTypeImg(item.type)
|
item.imgUrl = formatteTypeImg(item.type)
|
||||||
})
|
})
|
||||||
@ -169,41 +191,46 @@ const getPositionMapListFun = async (positionMapId) => {
|
|||||||
pointList.value = data
|
pointList.value = data
|
||||||
|
|
||||||
console.log(pointList.value)
|
console.log(pointList.value)
|
||||||
let lineStyle = calculateDistanceAndAngle({
|
let lineStyle = calculateDistanceAndAngle(
|
||||||
left: pointList.value[0].locationX,
|
{
|
||||||
top: pointList.value[0].locationY
|
left: pointList.value[0].locationX,
|
||||||
}, {
|
top: pointList.value[0].locationY
|
||||||
left: pointList.value[1].locationX,
|
},
|
||||||
top: pointList.value[1].locationY
|
{
|
||||||
})
|
left: pointList.value[1].locationX,
|
||||||
|
top: pointList.value[1].locationY
|
||||||
|
}
|
||||||
|
)
|
||||||
console.log(lineStyle)
|
console.log(lineStyle)
|
||||||
lineList.value = [{
|
lineList.value = [
|
||||||
...lineStyle,
|
{
|
||||||
color: '#1677ff',
|
...lineStyle,
|
||||||
height: 2,
|
color: '#1677ff',
|
||||||
}]
|
height: 2
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculateDistanceAndAngle = (point1, point2) => {
|
const calculateDistanceAndAngle = (point1, point2) => {
|
||||||
// 计算水平和垂直方向的差值
|
// 计算水平和垂直方向的差值
|
||||||
const dx = point2.left - point1.left;
|
const dx = point2.left - point1.left
|
||||||
const dy = point2.top - point1.top;
|
const dy = point2.top - point1.top
|
||||||
|
|
||||||
// 计算两点之间的长度(使用勾股定理)
|
// 计算两点之间的长度(使用勾股定理)
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
const distance = Math.sqrt(dx * dx + dy * dy)
|
||||||
|
|
||||||
// 计算两点连线与水平轴正方向的夹角(弧度)
|
// 计算两点连线与水平轴正方向的夹角(弧度)
|
||||||
const angleInRadians = Math.atan2(dy, dx);
|
const angleInRadians = Math.atan2(dy, dx)
|
||||||
|
|
||||||
// 将弧度转换为角度
|
// 将弧度转换为角度
|
||||||
const angleInDegrees = angleInRadians * (180 / Math.PI);
|
const angleInDegrees = angleInRadians * (180 / Math.PI)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
distance: distance,
|
distance: distance,
|
||||||
angle: angleInDegrees,
|
angle: angleInDegrees,
|
||||||
left: point1.left,
|
left: point1.left,
|
||||||
top: point1.top
|
top: point1.top
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatteTypeImg = (type) => {
|
const formatteTypeImg = (type) => {
|
||||||
@ -263,14 +290,14 @@ const getMapData = async (item) => {
|
|||||||
})
|
})
|
||||||
imgUrl.value = data
|
imgUrl.value = data
|
||||||
computedRatio()
|
computedRatio()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
const heightVal = ref(0)
|
||||||
const radio = ref(1)
|
const radio = ref(1)
|
||||||
const computedRatio = () => {
|
const computedRatio = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (imgUrl.value) {
|
if (imgUrl.value) {
|
||||||
let width = getElementWidthByClass('indexpage-container')
|
let width = getElementWidthByClass('indexpage-container')
|
||||||
getImageWidth(imgUrl.value).then((res) => {
|
getImageWidth(imgUrl.value,'width').then((res) => {
|
||||||
// console.log(res)
|
// console.log(res)
|
||||||
let ratioVal = width / res
|
let ratioVal = width / res
|
||||||
radio.value = ratioVal
|
radio.value = ratioVal
|
||||||
@ -280,16 +307,20 @@ const computedRatio = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
getImageWidth(imgUrl.value,'height').then((res) => {
|
||||||
|
console.log("高",res)
|
||||||
|
heightVal.value = res
|
||||||
|
})
|
||||||
// console.log(width)
|
// console.log(width)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getImageWidth = (imageUrl) => {
|
const getImageWidth = (imageUrl,name) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image()
|
const img = new Image()
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
resolve(img.width)
|
resolve(img[name])
|
||||||
}
|
}
|
||||||
img.onerror = function () {
|
img.onerror = function () {
|
||||||
reject(new Error('图片加载失败'))
|
reject(new Error('图片加载失败'))
|
||||||
@ -320,6 +351,8 @@ onBeforeUnmount(() => {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.affix-container {
|
.affix-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.indexpage-container {
|
.indexpage-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -379,14 +412,16 @@ onBeforeUnmount(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
.indexpage-container-box-point-item-inner-popover-item{
|
.indexpage-container-box-point-item-inner-popover-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-family: PingFangSC, PingFang SC;
|
font-family:
|
||||||
font-weight: 400;
|
PingFangSC,
|
||||||
font-size: 14px;
|
PingFang SC;
|
||||||
color: #0D162A;
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #0d162a;
|
||||||
}
|
}
|
||||||
.line-box{
|
.line-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user