Browse Source

TrafficTimeSpace 绿/蓝波带独立随机速度,文本改为水平显示:

  - mock apiGetTrafficTimeSpace:新增 speedKmhBackward 字段,正反两向各自 42~48 km/h
  随机(保留一位小数,互不相等);offset 仍按 speedKmh 反推,保证正向绿波完美对齐(反向蓝波接受漂移)
  - TrafficTimeSpace 组件新增 speedKmhBackward prop(默认 null 时回落到 speedKmh),getWaveData 分别用正反速度算
  greenTravelTime / blueTravelTime,每条波带带上自己的 speed 字段;速度文字渲染改用 item.speed
  - 速度文字 rotation 固定为 0(与 x 轴水平)
  - 波带中间的 {bandwidth}s 文字 rotation 也改为 0(与 x 轴水平)
  - watch 新增 speedKmhBackward 触发重绘
画安 1 week ago
parent
commit
1952969e62
2 changed files with 30 additions and 15 deletions
  1. 21 13
      src/components/ui/TrafficTimeSpace.vue
  2. 9 2
      src/mock/api.js

+ 21 - 13
src/components/ui/TrafficTimeSpace.vue

@@ -21,7 +21,8 @@ export default {
         { name: '交叉口D', distanceNext: 0, offset: 0 }
       ]
     },
-    speedKmh: { type: Number, default: 38.9 },     // 设计车速
+    speedKmh: { type: Number, default: 38.9 },     // 正向设计车速
+    speedKmhBackward: { type: Number, default: null }, // 反向设计车速;null 时用 speedKmh
     cycle: { type: Number, default: 100 },         // 红绿灯周期
     greenDuration: { type: Number, default: 40 },  // 绿灯时长
     bandwidth: { type: Number, default: 31.5 },    // 波带宽(秒)
@@ -98,6 +99,7 @@ export default {
   watch: {
     roadSegments: { handler() { this.updateChart(); }, deep: true },
     speedKmh() { this.updateChart(); },
+    speedKmhBackward() { this.updateChart(); },
     autoScroll(val) { val ? this.startScroll() : this.stopScroll(); }
   },
   methods: {
@@ -134,20 +136,24 @@ export default {
     },
 
     getWaveData() {
-      const speedMs = this.speedKmh / 3.6; // 设计车速换算为 m/s
+      const greenSpeed = this.speedKmh;
+      const blueSpeed = this.speedKmhBackward != null ? this.speedKmhBackward : this.speedKmh;
+      const greenMs = greenSpeed / 3.6;
+      const blueMs = blueSpeed / 3.6;
       const startX = this.intersections[0].x;
       const endX = this.intersections[this.intersections.length - 1].x;
-      const travelTime = (endX - startX) / speedMs;
+      const greenTravelTime = (endX - startX) / greenMs;
+      const blueTravelTime = (endX - startX) / blueMs;
 
       // 正向绿波 (A -> D):gStartY 秒起步
       const gStartY = 0;
       const greenBottomLine = [
         [startX, gStartY],
-        [endX, gStartY + travelTime]
+        [endX, gStartY + greenTravelTime]
       ];
       const greenTopLine = [
         [startX, gStartY + this.bandwidth],
-        [endX, gStartY + travelTime + this.bandwidth]
+        [endX, gStartY + greenTravelTime + this.bandwidth]
       ];
       const greenCoords = [...greenBottomLine, ...[...greenTopLine].reverse()];
 
@@ -155,11 +161,11 @@ export default {
       const bStartYAtD = 100;
       const blueBottomLine = [
         [endX, bStartYAtD],
-        [startX, bStartYAtD + travelTime]
+        [startX, bStartYAtD + blueTravelTime]
       ];
       const blueTopLine = [
         [endX, bStartYAtD + this.bandwidth],
-        [startX, bStartYAtD + travelTime + this.bandwidth]
+        [startX, bStartYAtD + blueTravelTime + this.bandwidth]
       ];
       const blueCoords = [...blueBottomLine, ...[...blueTopLine].reverse()];
 
@@ -170,7 +176,8 @@ export default {
           topLine: greenTopLine,
           color: this.upWaveColor,
           lineCol: '#2ecc71',
-          isBlue: false
+          isBlue: false,
+          speed: greenSpeed
         },
         {
           coords: blueCoords,
@@ -178,7 +185,8 @@ export default {
           topLine: blueTopLine,
           color: this.downWaveColor,
           lineCol: '#3498db',
-          isBlue: true
+          isBlue: true,
+          speed: blueSpeed
         }
       ];
     },
@@ -254,8 +262,8 @@ export default {
 
               // 波带角度统一用底线方向(atan2),保证文字沿着波带方向读
               const angle = Math.atan2(pB2[1] - pB1[1], pB2[0] - pB1[0]);
-              // 绿波速度文字沿波带方向顺时针 90°;蓝波沿波带方向逆时针 90°
-              const speedAngle = item.isBlue ? angle - Math.PI / 2 : angle + Math.PI / 2;
+              // 速度文字保持水平(与 x 轴平行)
+              const speedAngle = 0;
 
               const percent = 0.15;
               const midBottomX = pB1[0] + (pB2[0] - pB1[0]) * percent;
@@ -316,7 +324,7 @@ export default {
                       { type: 'polyline', shape: { points }, style: { stroke: item.lineCol, lineDash: [4, 4], lineWidth: 1 } }
                     ];
                   })(),
-                  { type: 'text', x: speedX, y: speedY, rotation: speedAngle, style: { text: `${this.speedKmh}km/h`, fill: '#fff', fontSize: this.fs(11), textAlign: 'center' } },
+                  { type: 'text', x: speedX, y: speedY, rotation: speedAngle, style: { text: `${item.speed}km/h`, fill: '#fff', fontSize: this.fs(11), textAlign: 'center' } },
                   ...(() => {
                     const cxBw = (midBottomX + midTopX) / 2;
                     const cyBw = (midBottomY + midTopY) / 2;
@@ -328,7 +336,7 @@ export default {
                     const gapBw = this.fs(10);
                     return [
                       { type: 'line', shape: { x1: midBottomX, y1: midBottomY, x2: cxBw - uxBw * gapBw, y2: cyBw - uyBw * gapBw }, style: { stroke: 'rgba(255, 255, 255, 0.4)' } },
-                      { type: 'text', x: cxBw, y: cyBw, rotation: angle, style: { text: `${this.bandwidth}s`, fill: '#fff', fontSize: this.fs(11), textAlign: 'center', textVerticalAlign: 'middle' } },
+                      { type: 'text', x: cxBw, y: cyBw, rotation: 0, style: { text: `${this.bandwidth}s`, fill: '#fff', fontSize: this.fs(11), textAlign: 'center', textVerticalAlign: 'middle' } },
                       { type: 'line', shape: { x1: cxBw + uxBw * gapBw, y1: cyBw + uyBw * gapBw, x2: midTopX, y2: midTopY }, style: { stroke: 'rgba(255, 255, 255, 0.4)' } }
                     ];
                   })()

+ 9 - 2
src/mock/api.js

@@ -650,8 +650,14 @@ export async function apiGetTrafficTimeSpace(opts = {}) {
   const dists = [450, 669, 1050, 0]
   const prefix = label || '交叉口'
 
-  // 设计车速 42~48 km/h 随机(保留一位小数)
-  const speedKmh = Math.round((42 + Math.random() * 6) * 10) / 10
+  // 正反两向设计车速各自 42~48 km/h 随机(保留一位小数),且两者不相同
+  const randSpeed = () => Math.round((42 + Math.random() * 6) * 10) / 10
+  const speedKmh = randSpeed()
+  let speedKmhBackward = randSpeed()
+  while (speedKmhBackward === speedKmh) {
+    speedKmhBackward = randSpeed()
+  }
+
   const cycle = 100
   const greenDuration = 40
   const bandwidth = 31.5
@@ -673,6 +679,7 @@ export async function apiGetTrafficTimeSpace(opts = {}) {
       offset: offsets[i]
     })),
     speedKmh,
+    speedKmhBackward,
     cycle,
     greenDuration,
     bandwidth,