Browse Source

TrafficTimeSpace 响应式字号与弹窗规格统一:

  - 新增 fs() 辅助方法基于 window.innerWidth/1920 做同比放大(>=1 不缩小),统一包裹
  axisLabel/nameTextStyle/速度/波带宽/路口名/相位差/距离标签等所有 fontSize,以及 grid padding、扫描线宽、标签 X/Y
  偏移(speedOff/gapBw/lineGap/labelX/centerYPx 等),解决大屏下文字偏小问题
  - barWidth、gap 由 data 改为 computed,按同样比例缩放,使柱高在大屏下同比放大
  - x 轴刻度改为仅显示红块首尾(每周期 0 与 greenDuration 位置),interval 自动取 gcd(greenDuration,
  cycle-greenDuration),axisLabel.formatter 过滤中间刻度
  - y 轴距离标签与虚线连接线的水平位置由 labelX-85 调整到 labelX-10,更贴近轴线
  - TrunkCoordination / StatusMonitoring / SpecialSituationMonitoring 三处 TrafficTimeSpace 弹窗规格统一为 width:1200 /
  height:700 / center:false / position:{x:500,y:150},与 CrossingMultiView 对齐
画安 1 week ago
parent
commit
d86b0ae587

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

@@ -45,11 +45,17 @@ export default {
       scanLineTimer: null,
       currentViewMinX: 0,
       currentScanX: 0,
-      barWidth: 8,
-      gap: 2,
     };
   },
   computed: {
+    barWidth() {
+      const scale = typeof window !== 'undefined' ? Math.max(1, window.innerWidth / 1920) : 1;
+      return Math.round(8 * scale);
+    },
+    gap() {
+      const scale = typeof window !== 'undefined' ? Math.max(1, window.innerWidth / 1920) : 1;
+      return Math.round(2 * scale);
+    },
     intersections() {
       let currentX = 0;
       return this.roadSegments.map((seg, i) => {
@@ -95,6 +101,12 @@ export default {
     autoScroll(val) { val ? this.startScroll() : this.stopScroll(); }
   },
   methods: {
+    // 根据大屏宽度缩放字号/像素常量,避免大屏下文字过小
+    fs(px) {
+      const scaled = typeof px2echarts === 'function' ? px2echarts(px) : px;
+      return Math.max(px, scaled);
+    },
+
     initChart() {
       if (!this.$refs.chartRef) return;
       this.$_chart = echarts.init(this.$refs.chartRef);
@@ -175,19 +187,31 @@ export default {
     updateChart() {
       if (!this.$_chart) return;
 
+      // x 轴刻度仅在红块首尾(每周期的 greenDuration 与 cycle 结束点)显示
+      const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
+      const redLen = this.cycle - this.greenDuration;
+      const tickInterval = redLen > 0 ? gcd(this.greenDuration, redLen) : this.greenDuration;
+
       const option = {
         backgroundColor: 'transparent',
         animation: false,
         tooltip: { show: false },
-        grid: { left: 140, right: 40, top: 40, bottom: 50 },
+        grid: { left: this.fs(140), right: this.fs(40), top: this.fs(40), bottom: this.fs(50) },
         xAxis: {
           type: 'value', min: this.currentViewMinX, max: this.currentViewMinX + this.viewWindow,
-          interval: 20, name: '时间 (秒)',
+          interval: tickInterval, name: '时间 (秒)',
           nameLocation: 'end',
-          nameTextStyle: { color: '#a0aabf', padding: [0, 0, 0, 0] },
+          nameTextStyle: { color: '#a0aabf', padding: [0, 0, 0, 0], fontSize: this.fs(12) },
           axisLine: { show: true, onZero: false, lineStyle: { color: 'rgba(255,255,255,0.15)' } },
           axisTick: { show: false },
-          axisLabel: { color: '#a0aabf', fontSize: 10 },
+          axisLabel: {
+            color: '#a0aabf',
+            fontSize: this.fs(10),
+            formatter: (value) => {
+              const mod = ((value % this.cycle) + this.cycle) % this.cycle;
+              return (mod === 0 || mod === this.greenDuration) ? value : '';
+            }
+          },
           splitLine: { show: this.showYSplitLine, lineStyle: { type: 'dashed', color: 'rgba(255, 255, 255, 0.08)' } }
         },
         yAxis: {
@@ -241,7 +265,7 @@ export default {
               const sPerpY = -sBDx / sBLen;
               const sDot = (pT1[0] - pB1[0]) * sPerpX + (pT1[1] - pB1[1]) * sPerpY;
               const sSign = sDot > 0 ? -1 : 1;
-              const speedOff = 14;
+              const speedOff = this.fs(14);
               const speedX = midBottomX + sSign * sPerpX * speedOff;
               const speedY = midBottomY + sSign * sPerpY * speedOff;
 
@@ -251,7 +275,7 @@ export default {
                   { type: 'polygon', shape: { points: mappedCoords }, style: { fill: item.color } },
                   ...(() => {
                     // 虚线与绿波带之间留间隙,沿垂直于底线方向向外偏移
-                    const lineGap = 4;
+                    const lineGap = this.fs(4);
                     const bDx = mappedBottom[1][0] - mappedBottom[0][0];
                     const bDy = mappedBottom[1][1] - mappedBottom[0][1];
                     const bLen = Math.sqrt(bDx * bDx + bDy * bDy) || 1;
@@ -268,7 +292,7 @@ export default {
                       { type: 'polyline', shape: { points: offsetBottom }, style: { stroke: item.lineCol, lineDash: [4, 4], lineWidth: 1 } }
                     ];
                   })(),
-                  { type: 'text', x: speedX, y: speedY, rotation: angle, style: { text: `${this.speedKmh}km/h`, fill: '#fff', fontSize: 11, textAlign: 'center' } },
+                  { type: 'text', x: speedX, y: speedY, rotation: angle, style: { text: `${this.speedKmh}km/h`, fill: '#fff', fontSize: this.fs(11), textAlign: 'center' } },
                   ...(() => {
                     const cxBw = (midBottomX + midTopX) / 2;
                     const cyBw = (midBottomY + midTopY) / 2;
@@ -277,10 +301,10 @@ export default {
                     const lenBw = Math.sqrt(dxBw * dxBw + dyBw * dyBw) || 1;
                     const uxBw = dxBw / lenBw;
                     const uyBw = dyBw / lenBw;
-                    const gapBw = 10;
+                    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: 11, textAlign: 'center', textVerticalAlign: 'middle' } },
+                      { type: 'text', x: cxBw, y: cyBw, rotation: angle, 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)' } }
                     ];
                   })()
@@ -320,7 +344,9 @@ export default {
               const intersection = this.intersections[params.dataIndex];
               const point = api.coord([this.currentViewMinX, intersection.x]);
               const centerYPx = point[1] + this.barWidth + this.gap / 2;
-              const labelX = point[0] - 12;
+              const labelX = point[0] - this.fs(12);
+              const nameFs = this.fs(12);
+              const subFs = this.fs(11);
 
               // 名称较长时按 "-" 拆成两行显示
               const dashIdx = intersection.name.indexOf('-');
@@ -329,14 +355,14 @@ export default {
 
               const children = [];
               if (nameLine2) {
-                children.push({ type: 'text', x: labelX, y: centerYPx - 15, style: { text: nameLine1, fill: '#fff', textAlign: 'right', fontSize: 12 } });
-                children.push({ type: 'text', x: labelX, y: centerYPx - 1, style: { text: nameLine2, fill: '#fff', textAlign: 'right', fontSize: 12 } });
+                children.push({ type: 'text', x: labelX, y: centerYPx - this.fs(15), style: { text: nameLine1, fill: '#fff', textAlign: 'right', fontSize: nameFs } });
+                children.push({ type: 'text', x: labelX, y: centerYPx - this.fs(1), style: { text: nameLine2, fill: '#fff', textAlign: 'right', fontSize: nameFs } });
               } else {
-                children.push({ type: 'text', x: labelX, y: centerYPx - 7, style: { text: nameLine1, fill: '#fff', textAlign: 'right', fontSize: 12 } });
+                children.push({ type: 'text', x: labelX, y: centerYPx - this.fs(7), style: { text: nameLine1, fill: '#fff', textAlign: 'right', fontSize: nameFs } });
               }
               if (this.showPhaseOffset) {
-                const offYPx = nameLine2 ? centerYPx + 14 : centerYPx + 5;
-                children.push({ type: 'text', x: labelX, y: offYPx, style: { text: `相位差: ${intersection.offsetText}`, fill: '#a0aabf', textAlign: 'right', fontSize: 11 } });
+                const offYPx = nameLine2 ? centerYPx + this.fs(14) : centerYPx + this.fs(5);
+                children.push({ type: 'text', x: labelX, y: offYPx, style: { text: `相位差: ${intersection.offsetText}`, fill: '#a0aabf', textAlign: 'right', fontSize: subFs } });
               }
 
               if (intersection.distanceNext) {
@@ -345,9 +371,9 @@ export default {
                 const midYPx = (centerYPx + nextCenterYPx) / 2;
 
                 // 非反转 yAxis:距离越大像素 y 越小,nextCenterYPx < centerYPx
-                const lineX = labelX - 85;
-                children.push({ type: 'line', shape: { x1: lineX, y1: centerYPx - 36, x2: lineX, y2: nextCenterYPx + 22 }, style: { stroke: 'rgba(255,255,255,0.1)', lineDash: [2, 2] } });
-                children.push({ type: 'text', x: lineX, y: midYPx, style: { text: `${intersection.distanceNext}m`, fill: '#a0aabf', textAlign: 'center', fontSize: 11 } });
+                const lineX = labelX - this.fs(10);
+                children.push({ type: 'line', shape: { x1: lineX, y1: centerYPx - this.fs(36), x2: lineX, y2: nextCenterYPx + this.fs(22) }, style: { stroke: 'rgba(255,255,255,0.1)', lineDash: [2, 2] } });
+                children.push({ type: 'text', x: lineX, y: midYPx, style: { text: `${intersection.distanceNext}m`, fill: '#a0aabf', textAlign: 'center', fontSize: subFs } });
               }
               return { type: 'group', children };
             }
@@ -364,7 +390,7 @@ export default {
               return {
                 type: 'line',
                 shape: { x1: top[0], y1: top[1], x2: bottom[0], y2: bottom[1] },
-                style: { stroke: this.scanLineColor, lineWidth: 4 }
+                style: { stroke: this.scanLineColor, lineWidth: this.fs(4) }
               };
             },
             z: 10

+ 4 - 3
src/views/SpecialSituationMonitoring.vue

@@ -560,9 +560,10 @@ export default {
                 id: nodeData.id,
                 title: nodeData.label + ' 绿波带',
                 component: 'TrafficTimeSpace',
-                width: 600,
-                height: 900,
-                center: true,
+                width: 1200,
+                height: 700,
+                center: false,
+                position: { x: 500, y: 150 },
                 showClose: true,
                 noPadding: false,
                 data: tsData,

+ 4 - 3
src/views/StatusMonitoring.vue

@@ -631,9 +631,10 @@ export default {
                 id: nodeData.id,
                 title: nodeData.label + ' 绿波带',
                 component: 'TrafficTimeSpace',
-                width: 600,
-                height: 900,
-                center: true,
+                width: 1200,
+                height: 700,
+                center: false,
+                position: { x: 500, y: 150 },
                 showClose: true,
                 noPadding: false,
                 data: tsData,

+ 4 - 3
src/views/TrunkCoordination.vue

@@ -568,9 +568,10 @@ export default {
                 id: nodeData.id,
                 title: nodeData.label + ' 绿波带',
                 component: 'TrafficTimeSpace',
-                width: 600,
-                height: 900,
-                center: true,
+                width: 1200,
+                height: 700,
+                center: false,
+                position: { x: 500, y: 150 },
                 showClose: true,
                 noPadding: false,
                 data: tsData,