Browse Source

feat: 地图图例动画

TwoKe945 1 year ago
parent
commit
d05e6de4c5

BIN
app/src/assets/images/legend-active-bg.png


BIN
app/src/assets/images/legend-bg.png


BIN
app/src/assets/images/legend-bg1.png


BIN
app/src/assets/images/legend-icon-bg.png


BIN
app/src/assets/images/login-bg.gif


+ 222 - 21
app/src/components/Map.vue

@@ -1,6 +1,6 @@
 <template>
-  <div class="map">
-    <div class="legend">
+  <div class="map" ref="map">
+    <div class="legend" v-if="false">
       <div class="item selected" v-if="data && data.showzhd">
         <img src="../assets/images/map-icon-fire.png" />火灾扑救
       </div>
@@ -85,7 +85,7 @@
     <div class="info-window" ref="infoWindow" v-if="firePoint">
       <div class="info-content">
         <div class="title">
-          <div class="txt">重点部位提醒</div>
+          <div class="txt">案发地址</div>
           <div class="close" @click="closeInfoWindow"></div>
         </div>
         <div class="content">
@@ -119,11 +119,10 @@ import mapIconFire from "../assets/images/map-icon-fire.png"; // 着火点
 import mapIconSzxhs from "../assets/images/map-icon-szxhs.png"; // 市政消火栓
 import mapIconTrsy from "../assets/images/map-icon-trsy.png"; // 天然水源
 import mapIconSfsc from "../assets/images/map-icon-xfsc.png"; // 消防水池
-
 import { getZy } from "@/api/map.js";
 export default {
   name: "MapContainer",
-  components: {},
+  components: { },
   data() {
     return {
       radius: 300,
@@ -183,6 +182,7 @@ export default {
           imageSize: [49, 53],
         },
       },
+      ops: {},
       showType: ["currentJzKey"],
       loading: false,
       markerCache: {
@@ -195,7 +195,9 @@ export default {
         "xfzKey": [],
         "jgKey": [],
         "xfcKey": []
-      }
+      },
+      legendWindow: null,
+      infoWindow: null
     };
   },
   props: {
@@ -225,6 +227,9 @@ export default {
       this.showType = ["currentJzKey"];
     }
     this.getData();
+    // this.$refs.map.addEventListener('click', () => {
+    //   this.$refs.mapLegend.close();
+    // })
   },
   methods: {
     changeType(type) {
@@ -240,7 +245,7 @@ export default {
         })
       } else {
         showType.push(type);
-        this.markerCache[type].forEach(marker => {
+        this.markerCache[type]?.forEach(marker => {
           this.map.add(marker)
         })
       }
@@ -301,14 +306,22 @@ export default {
       this.markers = markers;
       this.initMap().then(() => {
         if (this.showType.length === 1 && this.showType[0] === "currentJzKey") {
+          const p = this.markerCache['currentJzKey'][0]
+          this.addLegendWindow(p._position)
+          p.on("click",  (v) =>  {
+            this.openLegendWindow(p._position)
+          });
+          this.map.remove(p)
+          this.map.add(p)
+
           // 缓存所有的节点数据
-          console.log(res.data.filter(p => p.type !== 'currentJzKey' || p.type !== 'jzKey'))
           this.cacheAllMarkers(res.data.filter(p => p.type !== 'currentJzKey' || p.type !== 'jzKey').map(p => ({
             icon: p.type,
             position: [p.lon, p.lat],
             anchor: "bottom-center",
             data: JSON.parse(p.data),
           })))
+          
         }
       });
     },
@@ -326,9 +339,6 @@ export default {
             center: this.center, //初始化地图中心点位置
             mapStyle: "amap://styles/grey",
           });
-
-          // console.log(this.markers);
-
           // 设置覆盖物
           if (this.markers && this.markers.length > 0) {
             const markers = [];
@@ -402,7 +412,8 @@ export default {
               marker.on("mouseout", (e) => {
                 infoWindow.close();
               });
-              this.markerCache[type].push(marker)
+              this.markerCache[type].push(marker);
+              
               markers.push(marker);
             });
             this.map.add(markers);
@@ -424,15 +435,27 @@ export default {
       if (!this.firePoint) {
         return;
       }
-      const self = this;
       // 着火点
       var markerFire = new AMap.Marker({
         icon: mapIconFire,
         position: this.firePoint.position,
         anchor: "center",
       });
-      markerFire.on("click", function () {
-        self.addInfoWindow();
+      markerFire.on("click",  (v) =>  {
+        this.openLegendWindow(this.firePoint.position)
+      });
+      markerFire.on("mouseout",  (v) =>  {
+        this.infoWindow && this.infoWindow.close()
+      });
+      markerFire.on("mouseover",  (v) =>  {
+        // console.log()
+        this.infoWindow && this.infoWindow.open(
+          this.map,
+          new AMap.LngLat(this.firePoint.position[0], this.firePoint.position[1])
+        );
+      });
+      markerFire.on("click",  (v) =>  {
+        this.openLegendWindow(this.firePoint.position)
       });
       this.map.add(markerFire);
 
@@ -450,25 +473,90 @@ export default {
         fillOpacity: 0.08, // 填充透明度
       });
       this.map.add(circle);
-
-      // 信息窗口
-      this.addInfoWindow();
+      this.addLegendWindow(this.firePoint.position)
+      this.addInfoWindow()
     },
     addInfoWindow() {
       if (!this.firePoint) {
         return;
       }
       // 弹窗
-      var infoWindow = new AMap.InfoWindow({
+      this.infoWindow = new AMap.InfoWindow({
         isCustom: true,
         content: this.$refs.infoWindow,
         offset: new AMap.Pixel(0, -45),
         position: this.center,
       });
-      infoWindow.open(
+      // infoWindow.open(
+      //   this.map,
+      //   new AMap.LngLat(this.firePoint.position[0], this.firePoint.position[1])
+      // );
+    },
+    addLegendWindow(position) {
+      console.log(position)
+      const legend = [
+        { name: '消防车', key: 'xfcKey', icon: mapIconCar, width: '47.24px', height: '31px' },
+        { name: '微型消防站', key: 'xfzKey', icon: mapIconMicstation, width: '27.54px', height: '34px'  },
+        { name: '消防站', key: 'jgKey', icon: mapIconStation, width: '25.2px', height: '31px'  },
+        { name: '高层建筑', key: 'jzKey', icon: mapIconBuild, width: '25px', height: '34px'  },
+        { name: '市政消火栓', key: 'szxhsKey', icon: mapIconSzxhs, width: '25px', height: '32px'  },
+        { name: '天然水源', key: 'trsyKey', icon: mapIconTrsy, width: '25px', height: '34px' },
+        { name: '消防水池', key: 'xfscKey', icon: mapIconSfsc, width: '25px', height: '32px' },
+        { name: '室外消火栓', key: 'xhsKey', icon: mapIconSwxhs, width: '29px', height: '39px' }
+      ]
+      // 信息窗口
+      // this.addInfoWindow();
+
+      this.legendWindow = new AMap.InfoWindow({
+        isCustom: true,
+        content: `<div id="legendContainer" class='legend-container show-box'>
+          <div class="legend-list">
+            ${legend.map((item,idx) => {
+              const rotate = 360 / legend.length * idx;
+              return (`
+              <div class='legend-item show ${ this.showType.indexOf(item.key) > 0 ? "active": ""}' index='${idx}'
+              onclick='onClickLegendItem(${JSON.stringify({item, idx}).toString()})' style="--rotate: ${rotate}deg;" >
+                <div class='legend-content' style="transform: rotate(-${rotate}deg)">
+                  <img src="${item.icon}" width="${item.width}" height="${item.height}"/>
+                  <div>${item.name}</div>
+                </div>
+            </div>
+            `)
+            }).join('')}
+        </div>
+    <div onclick="closeMapLegend()" class="center-pointer"></div>
+          </div>`,
+        center: new AMap.LngLat(position[0], position[1]),
+      });
+      window.closeMapLegend = (e) => {
+        document.querySelector('#legendContainer').className = document.querySelector('#legendContainer').className.replace('show-box','close-box')
+        document.querySelectorAll('#legendContainer .legend-item').forEach(ele => {
+          ele.className = ele.className.replace('show','close')
+        })
+        setTimeout(() => {
+          this.legendWindow.close()
+        }, 650)
+      }
+      window.onClickLegendItem = (e) => {
+        const ele = this.legendWindow.dom.querySelector(`div.legend-item[index="${e.idx}"]`)
+        if (ele.className.indexOf("active") >= 0) {
+          ele.className = ele.className.replace('active', '')
+        } else {
+          ele.className += ' active'
+        }
+        this.changeType(e.item.key)
+      }
+    },
+    openLegendWindow(position) {
+      if (!this.legendWindow) return
+      this.legendWindow.open(
         this.map,
-        new AMap.LngLat(this.firePoint.position[0], this.firePoint.position[1])
+        new AMap.LngLat(position[0], position[1])
       );
+      document.querySelector('#legendContainer').className = document.querySelector('#legendContainer').className.replace('close-box', 'show-box')
+      document.querySelectorAll('#legendContainer .legend-item').forEach(ele => {
+        ele.className = ele.className.replace('close', 'show')
+      })
     },
     cacheAllMarkers(markerInfos) {
       if (markerInfos && markerInfos.length > 0) {
@@ -759,3 +847,116 @@ export default {
   }
 }
 </style>
+
+
+<style lang="less">
+@keyframes show-layer {
+  from {
+    transform: rotate(0deg) scale(0);
+  }
+  to {
+    transform: rotate(var(--rotate)) scale(1);
+  }
+}
+@keyframes close-layer {
+  from {
+    transform: rotate(var(--rotate)) scale(1);
+  }
+  to {
+    transform: rotate(0) scale(0);
+  }
+}
+
+@keyframes show-box  {
+  from {
+    transform: translate(-50%, -50%) scale(0);
+    opacity: 0;
+  }
+  to {
+    transform: translate(-50%, -50%) scale(1);
+    opacity: 1;
+  }
+}
+@keyframes close-box  {
+  from {
+    transform: translate(-50%, -50%) scale(1);
+    opacity: 1;
+  }
+  to {
+    transform: translate(-50%, -50%) scale(0);
+    opacity: 0;
+  }
+}
+
+.show-box {
+  animation: .8s linear show-box;
+}
+.close-box {
+  animation: .8s linear close-box;
+}
+
+.show {
+  animation: .8s linear show-layer;
+}
+.close {
+  animation: .8s linear close-layer;
+}
+
+.center-pointer {
+  width: 117px;
+  height: 87px;
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%, -50%);
+  cursor: pointer;
+}
+
+.legend-container {
+  position: fixed;
+  width: 507px;
+  height: 336px;
+  background: url('@/assets/images/legend-bg.png') no-repeat;
+  transform: translate(-50%, -50%);
+}
+.legend-list {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 300px;
+  height: 300px;
+}
+.legend-content {
+  position: absolute;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+.legend-item {
+  position: absolute;
+  display: block;
+  width: 91px;
+  height: 91px;
+  color: #ffffff;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  transition: all .8s;
+  /*改变旋转基点*/
+  transform-origin: 150px 150px;
+  /*最开始让小菜单隐藏*/
+  transform: scale(0);
+  border-radius: 50%;
+  background: url('@/assets/images/legend-icon-bg.png') no-repeat;
+  opacity: 1;
+  cursor: pointer;
+  transform: rotate(var(--rotate));
+  pointer-events: all;
+}
+
+.legend-item.active {
+  background: url('@/assets/images/legend-active-bg.png') no-repeat;
+}
+</style>

+ 1 - 1
app/src/views/Home/components/AlarmingSituationDynamics/AlaemList.vue

@@ -39,7 +39,7 @@
     <div>
       <div class="row header">
         <span class="time">警情类型</span>
-        <span class="person">地址</span>
+        <span class="person">案发地址</span>
         <span class="result">主站单位</span>
         <span class="result1">处置状态</span>
         <span class="result2">报警时间</span>

+ 1 - 1
app/src/views/PoliceSituation/components/Alarm.vue

@@ -15,7 +15,7 @@
 		<div>
 			<div class="row header">
 				<span class="time">警情类型</span>
-				<span class="person">地址</span>
+				<span class="person">案发地址</span>
 				<span class="result">主站单位</span>
 				<span class="result1">处置状态</span>
 				<span class="result2">报警时间</span>