|
|
@@ -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)' } }
|
|
|
];
|
|
|
})()
|