修复测距、框选 在定位元素内部的bug

This commit is contained in:
yyy 2025-02-15 10:33:28 +08:00
parent a769b54e7a
commit b3bd0635fc
3 changed files with 368 additions and 114 deletions

View File

@ -118,7 +118,6 @@
<div class="map-box" ref="imgWrap" :style="{ cursor: state.cursorStyle }"> <div class="map-box" ref="imgWrap" :style="{ cursor: state.cursorStyle }">
<div <div
class="map-box-inner" class="map-box-inner"
ref="image"
@mousedown.stop="startDrawSelection" @mousedown.stop="startDrawSelection"
@mousemove.stop="updateDrawSelection" @mousemove.stop="updateDrawSelection"
@mouseup.stop="endDrawSelection" @mouseup.stop="endDrawSelection"
@ -132,6 +131,7 @@
id="mapBg" id="mapBg"
/> />
<div <div
ref="mapBackgroundRef"
class="map-box-inner-dot" class="map-box-inner-dot"
@click="mapClick" @click="mapClick"
:class="state.isShowGrid ? 'grid-show' : ''" :class="state.isShowGrid ? 'grid-show' : ''"
@ -243,7 +243,6 @@
</div> </div>
<!-- 框选区域 --> <!-- 框选区域 -->
<template>
<div <div
v-for="(box, index) in state.allDrawSelectionAreaBox" v-for="(box, index) in state.allDrawSelectionAreaBox"
:key="index" :key="index"
@ -269,12 +268,11 @@
height: `${state.drawSelectionAreaBox.height}px`, height: `${state.drawSelectionAreaBox.height}px`,
border: '2px dashed #007bff', border: '2px dashed #007bff',
backgroundColor: 'rgba(0, 123, 255, 0.1)', backgroundColor: 'rgba(0, 123, 255, 0.1)',
zIndex: 999 zIndex: 9999
}" }"
></div> ></div>
</template>
<!-- 绘制点和连线 --> <!-- 测距 绘制点和连线 -->
<template v-if="state.measureDistancesPoints.length > 0"> <template v-if="state.measureDistancesPoints.length > 0">
<div <div
v-for="(point, index) in state.measureDistancesPoints" v-for="(point, index) in state.measureDistancesPoints"
@ -375,6 +373,7 @@ const lineLibrarySettingDialogRef = ref() //线库设置
const itemAreaSettingDialogRef = ref() // const itemAreaSettingDialogRef = ref() //
const equipmentToolDialogRef = ref() // const equipmentToolDialogRef = ref() //
const textFormToolDialogRef = ref() // const textFormToolDialogRef = ref() //
const mapBackgroundRef = ref()
const inputBoxRef = ref() // const inputBoxRef = ref() //
const message = useMessage() // const message = useMessage() //
@ -962,9 +961,19 @@ const rotationFormSubmit = () => {
// //
const startDrawSelection = (event) => { const startDrawSelection = (event) => {
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
const backgroundRect = mapBackgroundRef.value.getBoundingClientRect()
const x = Number(event.clientX) - backgroundRect.left
const y = event.clientY - backgroundRect.top
//
if (x >= 0 && x <= backgroundRect.width && y >= 0 && y <= backgroundRect.height) {
state.drawSelectionAreaShow = true state.drawSelectionAreaShow = true
state.drawSelectionStartPoint = { x: event.offsetX, y: event.offsetY } state.drawSelectionStartPoint = { x: x, y: y }
state.drawSelectionAreaBox = { x: event.offsetX, y: event.offsetY, width: 0, height: 0 } state.drawSelectionAreaBox = { x: x, y: y, width: 0, height: 0 }
}
// //
event.preventDefault() event.preventDefault()
} }
@ -972,8 +981,12 @@ const startDrawSelection = (event) => {
const updateDrawSelection = (event) => { const updateDrawSelection = (event) => {
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
if (state.drawSelectionAreaShow) { if (state.drawSelectionAreaShow) {
state.drawSelectionAreaBox.width = event.offsetX - state.drawSelectionStartPoint.x const backgroundRect = mapBackgroundRef.value.getBoundingClientRect()
state.drawSelectionAreaBox.height = event.offsetY - state.drawSelectionStartPoint.y const x = event.clientX - backgroundRect.left
const y = event.clientY - backgroundRect.top
state.drawSelectionAreaBox.width = Number(x) - Number(state.drawSelectionStartPoint.x)
state.drawSelectionAreaBox.height = Number(y) - Number(state.drawSelectionStartPoint.y)
} }
// //
event.preventDefault() event.preventDefault()
@ -1098,13 +1111,27 @@ const computedLineWidth = computed(() => {
// //
const measureDistancesClick = (event) => { const measureDistancesClick = (event) => {
//
const x = event.clientX
const y = event.clientY
//
const backgroundRect = mapBackgroundRef.value.getBoundingClientRect()
if (
x >= backgroundRect.left &&
x <= backgroundRect.right &&
y >= backgroundRect.top &&
y <= backgroundRect.bottom
) {
if (state.measureDistancesPoints.length === 2) { if (state.measureDistancesPoints.length === 2) {
// //
state.measureDistancesPoints = [] state.measureDistancesPoints = []
state.measureDistancesNum = null state.measureDistancesNum = null
} else { } else {
// //
state.measureDistancesPoints.push({ x: event.offsetX, y: event.offsetY }) const offsetX = x - backgroundRect.left
const offsetY = y - backgroundRect.top
state.measureDistancesPoints.push({ x: offsetX, y: offsetY })
if (state.measureDistancesPoints.length === 2) { if (state.measureDistancesPoints.length === 2) {
// //
state.measureDistancesNum = calculateDistance( state.measureDistancesNum = calculateDistance(
@ -1113,6 +1140,7 @@ const measureDistancesClick = (event) => {
) )
} }
} }
}
} }
// //

View File

@ -1,12 +1,64 @@
<template> <template>
<div @click="handleClick" style="position: relative; width: 100vw; height: 100vh"> <div>
<!-- 显示测量结果 --> <!-- 左侧菜单 -->
<div v-if="distance !== null" style="position: absolute; top: 20px; left: 20px"> <div
距离{{ distance.toFixed(2) }} 像素 style="
position: fixed;
left: 0;
top: 0;
width: 200px;
height: 100vh;
background-color: #f0f0f0;
"
>
左侧菜单
</div> </div>
<!-- 绘制点和连线 --> <!-- 背景区域 -->
<template v-if="points.length > 0"> <div
ref="background"
@mousedown="startSelection"
@mousemove="updateSelection"
@mouseup="endSelection"
style="margin-left: 200px; height: 100vh; position: relative; background-color: #fff"
>
<!-- 其他定位元素如图片 -->
<img
src="https://sys.znkjfw.com/imgs/process/%E8%AF%B7%E5%81%87.png"
style="position: absolute; top: 100px; left: 300px; width: 150px; height: 150px"
alt="示例图片"
/>
<!-- 绘制框选区域 -->
<div
v-for="(rect, index) in selectionRects"
:key="index"
:style="{
position: 'absolute',
left: `${rect.x}px`,
top: `${rect.y}px`,
width: `${rect.width}px`,
height: `${rect.height}px`,
border: '2px solid blue',
backgroundColor: 'rgba(0, 0, 255, 0.1)'
}"
></div>
<!-- 当前框选区域 -->
<div
v-if="isSelecting"
:style="{
position: 'absolute',
left: `${selectionBox.x}px`,
top: `${selectionBox.y}px`,
width: `${selectionBox.width}px`,
height: `${selectionBox.height}px`,
border: '2px dashed red',
backgroundColor: 'rgba(255, 0, 0, 0.1)'
}"
></div>
<!-- 绘制点位 -->
<div <div
v-for="(point, index) in points" v-for="(point, index) in points"
:key="index" :key="index"
@ -16,85 +68,104 @@
top: `${point.y}px`, top: `${point.y}px`,
width: '10px', width: '10px',
height: '10px', height: '10px',
backgroundColor: '#00329F', backgroundColor: isPointSelected(point) ? 'red' : 'black',
borderRadius: '50%' borderRadius: '50%'
}" }"
></div> ></div>
<div </div>
v-if="points.length === 2"
:style="{ <!-- 确定按钮 -->
position: 'absolute', <button @click="confirmSelection" style="position: fixed; top: 20px; left: 220px">
left: `${points[0].x + 5}px`, 确定
top: `${points[0].y + 5}px`, </button>
width: `${lineWidth}px`,
height: '2px',
backgroundColor: '#00329F',
transform: `rotate(${lineAngle}deg)`,
transformOrigin: '0 0',
textAlign: 'center'
}"
>
距离{{ distance.toFixed(2) }} 像素</div
>
</template>
</div> </div>
</template> </template>
<script> <script>
import { ref, computed } from 'vue' import { ref, computed, onMounted } from 'vue'
export default { export default {
setup() { setup() {
const points = ref([]) // const background = ref(null) // DOM
const distance = ref(null) // const points = ref([
{ x: 10, y: 10 },
{ x: 30, y: 100 },
{ x: 40, y: 40 },
{ x: 230, y: 400 },
{ x: 750, y: 640 }
]) //
const isSelecting = ref(false) //
const selectionBox = ref({ x: 0, y: 0, width: 0, height: 0 }) //
const selectionRects = ref([]) //
const startPos = ref({ x: 0, y: 0 }) //
// //
const calculateDistance = (point1, point2) => { const isPointInRect = (point, rect) => {
const dx = point2.x - point1.x return (
const dy = point2.y - point1.y point.x >= rect.x &&
return Math.sqrt(dx * dx + dy * dy) point.x <= rect.x + rect.width &&
point.y >= rect.y &&
point.y <= rect.y + rect.height
)
} }
// 线 //
const lineAngle = computed(() => { const isPointSelected = (point) => {
if (points.value.length === 2) { return selectionRects.value.some((rect) => isPointInRect(point, rect))
const dx = points.value[1].x - points.value[0].x
const dy = points.value[1].y - points.value[0].y
return Math.atan2(dy, dx) * (180 / Math.PI)
} }
return 0
})
// 线 //
const lineWidth = computed(() => { const startSelection = (event) => {
if (points.value.length === 2) { const backgroundRect = background.value.getBoundingClientRect()
return calculateDistance(points.value[0], points.value[1]) const x = event.clientX - backgroundRect.left
} const y = event.clientY - backgroundRect.top
return 0
})
// //
const handleClick = (event) => { if (x >= 0 && x <= backgroundRect.width && y >= 0 && y <= backgroundRect.height) {
if (points.value.length === 2) { isSelecting.value = true
// startPos.value = { x, y }
points.value = [] selectionBox.value = { x, y, width: 0, height: 0 }
distance.value = null
} else {
//
points.value.push({ x: event.offsetX, y: event.offsetY })
if (points.value.length === 2) {
//
distance.value = calculateDistance(points.value[0], points.value[1])
} }
} }
//
const updateSelection = (event) => {
if (isSelecting.value) {
const backgroundRect = background.value.getBoundingClientRect()
const x = event.clientX - backgroundRect.left
const y = event.clientY - backgroundRect.top
selectionBox.value.width = x - startPos.value.x
selectionBox.value.height = y - startPos.value.y
}
}
//
const endSelection = () => {
if (isSelecting.value) {
isSelecting.value = false
selectionRects.value.push({ ...selectionBox.value })
}
}
//
const confirmSelection = () => {
const selectedPoints = points.value.filter((point) => isPointSelected(point))
console.log('选中的点位:', selectedPoints)
alert(`选中的点位:${JSON.stringify(selectedPoints)}`)
} }
return { return {
background,
points, points,
distance, isSelecting,
lineAngle, selectionBox,
lineWidth, selectionRects,
handleClick startSelection,
updateSelection,
endSelection,
confirmSelection,
isPointSelected
} }
} }
} }

View File

@ -0,0 +1,155 @@
<template>
<div>
<!-- 左侧菜单 -->
<div
style="
position: fixed;
left: 0;
top: 0;
width: 200px;
height: 100vh;
background-color: #f0f0f0;
"
>
左侧菜单
</div>
<!-- 背景区域 -->
<div
ref="background"
style="margin-left: 200px; height: 100vh; position: relative; background-color: #fff"
>
<!-- 其他定位元素如图片 -->
<img
src="https://sys.znkjfw.com/imgs/process/%E8%AF%B7%E5%81%87.png"
style="position: absolute; top: 100px; left: 300px; width: 150px; height: 150px"
alt="示例图片"
/>
<!-- 显示测量结果 -->
<div v-if="distance !== null" style="position: absolute; top: 20px; left: 220px">
距离{{ distance.toFixed(2) }} 像素
</div>
<!-- 绘制点和连线 -->
<template v-if="points.length > 0">
<div
v-for="(point, index) in points"
:key="index"
:style="{
position: 'absolute',
left: `${point.x}px`,
top: `${point.y}px`,
width: '10px',
height: '10px',
backgroundColor: 'red',
borderRadius: '50%'
}"
></div>
<div
v-if="points.length === 2"
:style="{
position: 'absolute',
left: `${points[0].x}px`,
top: `${points[0].y}px`,
width: `${lineWidth}px`,
height: '2px',
backgroundColor: 'blue',
transform: `rotate(${lineAngle}deg)`,
transformOrigin: '0 0'
}"
></div>
</template>
</div>
</div>
</template>
<script>
import { ref, computed, onMounted, onUnmounted } from 'vue'
export default {
setup() {
const background = ref(null) // DOM
const points = ref([]) //
const distance = ref(null) //
//
const calculateDistance = (point1, point2) => {
const dx = point2.x - point1.x
const dy = point2.y - point1.y
return Math.sqrt(dx * dx + dy * dy)
}
// 线
const lineAngle = computed(() => {
if (points.value.length === 2) {
const dx = points.value[1].x - points.value[0].x
const dy = points.value[1].y - points.value[0].y
return Math.atan2(dy, dx) * (180 / Math.PI)
}
return 0
})
// 线
const lineWidth = computed(() => {
if (points.value.length === 2) {
return calculateDistance(points.value[0], points.value[1])
}
return 0
})
//
const handleClick = (event) => {
//
const x = event.clientX
const y = event.clientY
//
const backgroundRect = background.value.getBoundingClientRect()
if (
x >= backgroundRect.left &&
x <= backgroundRect.right &&
y >= backgroundRect.top &&
y <= backgroundRect.bottom
) {
if (points.value.length === 2) {
//
points.value = []
distance.value = null
} else {
//
const offsetX = x - backgroundRect.left
const offsetY = y - backgroundRect.top
points.value.push({ x: offsetX, y: offsetY })
if (points.value.length === 2) {
//
distance.value = calculateDistance(points.value[0], points.value[1])
}
}
}
}
//
onMounted(() => {
window.addEventListener('click', handleClick)
})
//
onUnmounted(() => {
window.removeEventListener('click', handleClick)
})
return {
background,
points,
distance,
lineAngle,
lineWidth
}
}
}
</script>
<style scoped>
/* 样式可以根据需要调整 */
</style>