feat(tunnel): 优化隧道区域热点功能
- 重构了 SVG 图层和热区生成逻辑,支持动态渲染多个区域 - 添加了鼠标悬停和点击事件处理,优化了用户交互体验 - 优化了坐标转换函数,提高了热区精度 - 调整了样式和布局,提升了整体视觉效果
This commit is contained in:
@@ -8,11 +8,31 @@
|
|||||||
|
|
||||||
<div style="display: flex;justify-content: center;align-items: center;position: relative;">
|
<div style="display: flex;justify-content: center;align-items: center;position: relative;">
|
||||||
<img src="/images/img.png" alt="" class="imgModel" id="imgModel" usemap="#image" @click="handleImageClick"/>
|
<img src="/images/img.png" alt="" class="imgModel" id="imgModel" usemap="#image" @click="handleImageClick"/>
|
||||||
<svg width="1040" height="650" viewBox="0 0 600 700" xmlns="http://www.w3.org/2000/svg" style="position: absolute;left: -232px;top: 32px" title="厂房" v-if="showAarea10">
|
|
||||||
<!-- points 字符串格式 "x1,y1 x2,y2 x3,y3 ..." -->
|
<!-- 为coordsList中的每个元素创建对应的SVG图层 -->
|
||||||
<polygon id="poly" points="127,418 165,415 175,440 136,556 98,558 106,478"
|
<svg
|
||||||
fill="rgba(0,150,255,0.3)" stroke="#0077cc" stroke-width="2" @click="clickHot(98,0)" style="cursor: pointer; pointer-events: auto;"/>
|
v-for="(item, index) in coordsList"
|
||||||
|
:key="index"
|
||||||
|
width="1040"
|
||||||
|
height="646"
|
||||||
|
viewBox="0 0 600 700"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
style="position: absolute; pointer-events: none;"
|
||||||
|
:style="hoveredAreaIndex==0?'left: -232px;top: 32px; ':hoveredAreaIndex==1?'left: -180px;top: 20px;':'left: -180px;top: 10px;'"
|
||||||
|
:title="item.title"
|
||||||
|
v-show="hoveredAreaIndex == index"
|
||||||
|
>
|
||||||
|
<polygon
|
||||||
|
:id="'poly' + index"
|
||||||
|
:points="convertCoordsToPoints(item.coords)"
|
||||||
|
fill="rgba(0,150,255,0.3)"
|
||||||
|
stroke="#0077cc"
|
||||||
|
stroke-width="2"
|
||||||
|
style="cursor: pointer; pointer-events: none"
|
||||||
|
@click="clickHot(item.tunnelId, item.clickIndex, index)"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<!-- 测量模式控制按钮 -->
|
<!-- 测量模式控制按钮 -->
|
||||||
<!-- <div v-if="isMeasuring" style="position: absolute; top: 20px; right: 20px; z-index: 1000;">-->
|
<!-- <div v-if="isMeasuring" style="position: absolute; top: 20px; right: 20px; z-index: 1000;">-->
|
||||||
<!-- <button @click.stop="toggleMeasurementMode" -->
|
<!-- <button @click.stop="toggleMeasurementMode" -->
|
||||||
@@ -32,8 +52,9 @@
|
|||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
<map name="image" id="image">
|
<map name="image" id="image">
|
||||||
<area shape="poly" v-for="(item,index) in coordsList" :coords="item.coords" :key="index" alt="" :id="'area'+index"
|
<area shape="poly" v-for="(item,index) in coordsList" :coords="item.coords" :key="index" alt=""
|
||||||
:title="item.title" style="cursor: pointer;" >
|
:id="'area'+index"
|
||||||
|
:title="item.title" style="cursor: pointer;pointer-events: none">
|
||||||
<!-- :href="'/' + item.tunnelId + '/' + siteId" @click="clickHot(item.tunnelId,item.clickIndex)"-->
|
<!-- :href="'/' + item.tunnelId + '/' + siteId" @click="clickHot(item.tunnelId,item.clickIndex)"-->
|
||||||
</map>
|
</map>
|
||||||
</div>
|
</div>
|
||||||
@@ -314,7 +335,8 @@ import { ElMessage, ElMessageBox } from "element-plus";
|
|||||||
import {getUserInfo} from "@/api/login";
|
import {getUserInfo} from "@/api/login";
|
||||||
import {initSceneData} from "@/api/tunnelScene";
|
import {initSceneData} from "@/api/tunnelScene";
|
||||||
import {getTunnelList} from "@/api/tunnelManage";
|
import {getTunnelList} from "@/api/tunnelManage";
|
||||||
import { debounce } from "lodash";
|
import {debounce, unset} from "lodash";
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const previewId = reactive(router.currentRoute.value.params.tunnelId);
|
const previewId = reactive(router.currentRoute.value.params.tunnelId);
|
||||||
@@ -353,7 +375,6 @@ const routeList = ref([]);
|
|||||||
let socket = reactive("");
|
let socket = reactive("");
|
||||||
let pattern = reactive(new RegExp("[A-Za-z]+"));
|
let pattern = reactive(new RegExp("[A-Za-z]+"));
|
||||||
let isTunnel = reactive(false);
|
let isTunnel = reactive(false);
|
||||||
let showAarea10 = ref(false);
|
|
||||||
const coordsList = ref([
|
const coordsList = ref([
|
||||||
{
|
{
|
||||||
//厂房
|
//厂房
|
||||||
@@ -376,6 +397,23 @@ const coordsList = ref([
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 添加hoveredAreaIndex用于跟踪当前悬停的区域索引
|
||||||
|
const hoveredAreaIndex = ref(-1);
|
||||||
|
// 添加用于存储定时器的数组
|
||||||
|
const hoverTimeouts = ref([]);
|
||||||
|
|
||||||
|
// 添加用于转换坐标格式的函数
|
||||||
|
const convertCoordsToPoints = (coords) => {
|
||||||
|
// 将 "x1,y1,x2,y2,..." 格式转换为 "x1,y1 x2,y2 ..." 格式
|
||||||
|
const coordsArray = coords.split(',');
|
||||||
|
let points = '';
|
||||||
|
for (let i = 0; i < coordsArray.length; i += 2) {
|
||||||
|
if (i > 0) points += ' ';
|
||||||
|
points += coordsArray[i] + ',' + coordsArray[i + 1];
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
};
|
||||||
|
|
||||||
const btnList = ref([
|
const btnList = ref([
|
||||||
{
|
{
|
||||||
route: "/site",
|
route: "/site",
|
||||||
@@ -461,14 +499,14 @@ nextTick(() => {
|
|||||||
|
|
||||||
// 设置hover状态
|
// 设置hover状态
|
||||||
isHovered = true;
|
isHovered = true;
|
||||||
showAarea10.value = true;
|
hoveredAreaIndex.value = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
area1.addEventListener("mousemove", e => {
|
area1.addEventListener("mousemove", e => {
|
||||||
// 鼠标在区域内移动时保持显示状态
|
// 鼠标在区域内移动时保持显示状态
|
||||||
if (!isHovered) {
|
if (!isHovered) {
|
||||||
isHovered = true;
|
isHovered = true;
|
||||||
showAarea10.value = true;
|
hoveredAreaIndex.value = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -481,7 +519,7 @@ nextTick(() => {
|
|||||||
|
|
||||||
hoverTimeout = setTimeout(() => {
|
hoverTimeout = setTimeout(() => {
|
||||||
isHovered = false;
|
isHovered = false;
|
||||||
showAarea10.value = false;
|
hoveredAreaIndex.value = -1;
|
||||||
}, 100); // 100ms延迟
|
}, 100); // 100ms延迟
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -505,12 +543,17 @@ const coordsData = [
|
|||||||
const result = convertCoordsToArray(coordsData);
|
const result = convertCoordsToArray(coordsData);
|
||||||
console.log(result);
|
console.log(result);
|
||||||
// 输出: "163,487,153,483,217,480,170,644,111,640,145,483"
|
// 输出: "163,487,153,483,217,480,170,644,111,640,145,483"
|
||||||
const clickHot = (id,index) => {
|
const clickHot = (id, index, areaIndex) => {
|
||||||
console.log('点击热区===============')
|
console.log('点击热区===============')
|
||||||
initialIndex.value = index
|
initialIndex.value = index
|
||||||
changeTunnel(index)
|
changeTunnel(index)
|
||||||
tunnelBtn.value.setActiveItem(index);
|
tunnelBtn.value.setActiveItem(index);
|
||||||
|
|
||||||
|
// 点击时也设置hoveredAreaIndex,确保点击的区域高亮显示
|
||||||
|
if (areaIndex !== undefined) {
|
||||||
|
hoveredAreaIndex.value = areaIndex;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
const changeName = (id) => {
|
const changeName = (id) => {
|
||||||
for (let item of equipmentOption.value) {
|
for (let item of equipmentOption.value) {
|
||||||
if (item.value === id) {
|
if (item.value === id) {
|
||||||
@@ -945,31 +988,31 @@ const clearMeasurementPoints = () => {
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.alarm-tunnel .device-table {
|
.alarm-tunnel .device-table {
|
||||||
|
|
||||||
height: 1158px !important;
|
height: 1158px !important;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
||||||
.el-dialog__body {
|
.el-dialog__body {
|
||||||
height: 1158px !important;
|
height: 1158px !important;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 滚动条轨道
|
|
||||||
&::-webkit-scrollbar-track {
|
&::-webkit-scrollbar-track {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 小滑块
|
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
background: rgb(8, 183, 184);
|
background: rgb(8, 183, 184);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-drawer__header {
|
.el-drawer__header {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -981,7 +1024,6 @@ const clearMeasurementPoints = () => {
|
|||||||
|
|
||||||
.el-dropdown__popper.el-popper {
|
.el-dropdown__popper.el-popper {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
//border: none;
|
|
||||||
border: 1px solid #0e7daa;
|
border: 1px solid #0e7daa;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
@@ -1001,9 +1043,7 @@ const clearMeasurementPoints = () => {
|
|||||||
|
|
||||||
.el-dropdown-menu__item {
|
.el-dropdown-menu__item {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
//border:none;
|
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
||||||
border-bottom: 1px solid #05feff;
|
border-bottom: 1px solid #05feff;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
@@ -1024,22 +1064,21 @@ const clearMeasurementPoints = () => {
|
|||||||
background: rgba(7, 35, 72, 0.9);
|
background: rgba(7, 35, 72, 0.9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.points {
|
.points {
|
||||||
background-color: red;
|
background-color: red;
|
||||||
z-index: 2222222222222222222;
|
z-index: 2222222222222222222;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main {
|
#main {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
//background-color: #072348;
|
|
||||||
background-image: url('/images/background/background.png');
|
background-image: url('/images/background/background.png');
|
||||||
|
|
||||||
#tunnel-box {
|
#tunnel-box {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-box {
|
.img-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -1050,6 +1089,7 @@ const clearMeasurementPoints = () => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.imgModel {
|
.imgModel {
|
||||||
width: 1040px;
|
width: 1040px;
|
||||||
height: 646px;
|
height: 646px;
|
||||||
@@ -1069,7 +1109,6 @@ const clearMeasurementPoints = () => {
|
|||||||
|
|
||||||
:deep(.el-table--fit) {
|
:deep(.el-table--fit) {
|
||||||
width: auto;
|
width: auto;
|
||||||
//height: 600px;
|
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
|
|
||||||
.el-loading-mask {
|
.el-loading-mask {
|
||||||
@@ -1087,7 +1126,6 @@ const clearMeasurementPoints = () => {
|
|||||||
:deep(.el-table__empty-block) {
|
:deep(.el-table__empty-block) {
|
||||||
height: 200px !important;
|
height: 200px !important;
|
||||||
|
|
||||||
//display: none;
|
|
||||||
.el-table__empty-text {
|
.el-table__empty-text {
|
||||||
font-size: 60px;
|
font-size: 60px;
|
||||||
color: #08b7b8;
|
color: #08b7b8;
|
||||||
@@ -1233,7 +1271,6 @@ const clearMeasurementPoints = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-table--fit) {
|
:deep(.el-table--fit) {
|
||||||
//width: 1780px !important;
|
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1248,9 +1285,7 @@ const clearMeasurementPoints = () => {
|
|||||||
background-color: #1c5971;
|
background-color: #1c5971;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell) {
|
||||||
.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell
|
|
||||||
) {
|
|
||||||
background-color: #1c5971;
|
background-color: #1c5971;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1258,12 +1293,7 @@ const clearMeasurementPoints = () => {
|
|||||||
background-color: #13849c !important;
|
background-color: #13849c !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(
|
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell) {
|
||||||
.el-table--striped
|
|
||||||
.el-table__body
|
|
||||||
tr.el-table__row--striped
|
|
||||||
td.el-table__cell
|
|
||||||
) {
|
|
||||||
background-color: #13849c !important;
|
background-color: #13849c !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user