ソースを参照

feat: 优化地图标记显示,实现稀疏化和视觉层次

sequoia tungfang 1 ヶ月 前
コミット
1b1664ceca
共有1 個のファイルを変更した90 個の追加28 個の削除を含む
  1. 90 28
      src/components/TongzhouTrafficMap.vue

+ 90 - 28
src/components/TongzhouTrafficMap.vue

@@ -133,7 +133,7 @@ export default {
   },
   methods: {
     // 检查地图环境是否安全可用
-    isMapSafe() {
+    isMapReady() {
       return !this._isDestroyed && this.map && typeof this.map.add === 'function';
     },
 
@@ -155,7 +155,7 @@ export default {
 
     updateMapDisplay() {
       if (this.infoWindow) this.infoWindow.close();
-      if (!this.isMapSafe()) return;
+      if (!this.isMapReady()) return;
 
       Object.keys(this.routeGroups).forEach(name => {
         const overlays = this.routeGroups[name];
@@ -196,13 +196,20 @@ export default {
       }
     },
 
+
+
+    // ... 其他代码保持不变
+    isMapReady() {
+      return !this._isDestroyed && this.map && typeof this.map.add === 'function';
+    },
+
     drawStaticRoutes() {
-      if (!this.isMapSafe()) return;
+      if (!this.isMapReady()) return;
 
       this.legendConfig.forEach((config, index) => {
-        // 使用闭包防止异步回调拿到错误的 index 或 config
+        // 使用箭头函数保持 this 指向 Vue 实例
         setTimeout(() => {
-          if (!this.isMapSafe()) return;
+          if (!this.isMapReady()) return;
 
           const driving = new this.AMap.Driving({
             map: null,
@@ -210,9 +217,10 @@ export default {
             autoFitView: false
           });
 
+          // 这里必须用箭头函数 (status, result) => { ... }
           driving.search(config.start, config.end, (status, result) => {
-            // 搜索结果返回时,组件可能已销毁
-            if (!this.isMapSafe()) return;
+            // 这里的 this 才能访问到 isMapReady
+            if (!this.isMapReady()) return;
 
             let path = [];
             if (status === 'complete' && result.routes[0]) {
@@ -224,30 +232,30 @@ export default {
             const markers = [];
             let polyline = null;
 
+            // 路线逻辑
             if (["干线协调", "勤务路线"].includes(config.name)) {
               polyline = new this.AMap.Polyline({
                 path: path,
                 strokeColor: config.color,
-                strokeWeight: 8,
-                strokeOpacity: 0.8,
+                strokeWeight: 6,
+                strokeOpacity: 0.6,
                 zIndex: 15
               });
             }
 
-            // 抽稀取点逻辑
-            const step = 10;
-            for (let i = 0; i < path.length; i += step) {
+            // --- 稀疏化逻辑 ---
+            const isAbnormalStatus = ["离线", "降级", "故障"].includes(config.name);
+            // 异常状态(离线等)每 40 个点取一个,普通状态每 15 个点取一个
+            const stepSize = isAbnormalStatus ? 40 : 15;
+
+            for (let i = 0; i < path.length; i += stepSize) {
               markers.push(this.createTrafficLightMarker(path[i], config));
             }
-            if ((path.length - 1) % step !== 0) {
-              markers.push(this.createTrafficLightMarker(path[path.length - 1], config));
-            }
 
             const overlays = [...markers, polyline].filter(Boolean);
             this.routeGroups[config.name] = overlays;
 
-            // 最终添加到地图前再检查一次
-            if (this.isMapSafe() && this.activeLegends.includes(config.name)) {
+            if (this.isMapReady() && this.activeLegends.includes(config.name)) {
               this.map.add(overlays);
             }
           });
@@ -256,25 +264,44 @@ export default {
     },
 
     createTrafficLightMarker(position, config) {
-      const needsFlash = ["离线", "降级", "故障"].includes(config.name);
+      const isAbnormal = ["离线", "降级", "故障"].includes(config.name);
       const lng = Number(position[0] || position.lng);
       const lat = Number(position[1] || position.lat);
 
+      // 3. 【视觉优化】调整 Marker 大小比例
+      // 异常状态图标略大(为了警示),普通点位略小且半透明
+      const size = isAbnormal ? '18px' : '14px';
+      const opacity = isAbnormal ? '1' : '0.85';
+      const shadow = isAbnormal ? `0 0 10px ${config.color}` : `0 0 5px ${config.color}`;
+
       const marker = new this.AMap.Marker({
         position: [lng, lat],
-        zIndex: 100,
+        zIndex: isAbnormal ? 110 : 100, // 异常图标显示在更上层
         content: `
-          <div class="pure-light-node ${needsFlash ? 'breathe' : ''}" 
-              style="background: ${config.color}; box-shadow: 0 0 15px ${config.color}; font-size: 12px; display: flex; justify-content: center; align-items: center; color: #fff; padding: 8px;">
-            <span>${config.name.charAt(0)}</span>
+          <div class="pure-light-node ${isAbnormal ? 'breathe abnormal-node' : ''}" 
+              style="
+                width: ${size}; 
+                height: ${size}; 
+                background: ${config.color}; 
+                box-shadow: ${shadow}; 
+                opacity: ${opacity};
+                border: 1.5px solid rgba(255,255,255,0.7);
+                font-size: 12px;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                color: #fff;
+                padding: 8px;
+              ">
+            <span style="transform: scale(0.7); font-weight: bold;">${config.name.charAt(0)}</span>
           </div>
         `,
-        offset: new this.AMap.Pixel(-10, -10),
+        offset: new this.AMap.Pixel(-8, -8),
         extData: {
           ...config,
           position: [lng, lat],
           statusColor: config.color,
-          statusLabel: needsFlash ? config.name : "正常运行",
+          statusLabel: isAbnormal ? config.name : "正常运行",
           road: '北京路与南京路',
           time: '2026.1.23.12:00'
         }
@@ -289,7 +316,7 @@ export default {
     },
 
     openLightInfo(data, position) {
-      if (!this.isMapSafe()) return;
+      if (!this.isMapReady()) return;
 
       const content = `
         <div class="custom-info-card">
@@ -323,7 +350,7 @@ export default {
 
     toggleAll() {
       const targetState = !this.isAllSelected;
-      if (!this.isMapSafe()) return;
+      if (!this.isMapReady()) return;
 
       if (targetState) {
         this.activeLegends = this.legendConfig.map(item => item.name);
@@ -340,7 +367,7 @@ export default {
     },
 
     toggleRouteVisible(name) {
-      if (!this.isMapSafe()) return;
+      if (!this.isMapReady()) return;
 
       const overlays = this.routeGroups[name] || [];
       const index = this.activeLegends.indexOf(name);
@@ -355,7 +382,7 @@ export default {
     },
 
     focusByLocation(targetPos) {
-      if (!this.isMapSafe() || !targetPos || targetPos.length !== 2) return;
+      if (!this.isMapReady() || !targetPos || targetPos.length !== 2) return;
 
       let foundMarker = null;
       Object.values(this.routeGroups).forEach(group => {
@@ -704,4 +731,39 @@ export default {
   object-fit: contain;
   display: block;
 }
+
+::v-deep .pure-light-node {
+  border-radius: 50%;
+  cursor: pointer;
+  transition: all 0.3s;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: #fff;
+  pointer-events: auto;
+  /* 确保能点击 */
+}
+
+/* 异常状态增加稍微剧烈一点的呼吸感,但缩小范围 */
+@keyframes light-breathe {
+  0% {
+    transform: scale(0.9);
+    opacity: 0.8;
+  }
+
+  50% {
+    transform: scale(1.1);
+    opacity: 1;
+  }
+
+  100% {
+    transform: scale(0.9);
+    opacity: 0.8;
+  }
+}
+
+/* 首页展示时,如果觉得还是太密,可以给非异常节点降权 */
+::v-deep .pure-light-node:not(.abnormal-node) {
+  border: 1px solid rgba(255, 255, 255, 0.4);
+}
 </style>