|
|
@@ -22,15 +22,18 @@ export default {
|
|
|
downWaveColor: { type: String, default: 'rgba(104, 231, 95, 0.4)' },
|
|
|
waveLabelColor: { type: String, default: '#e0f7fa' },
|
|
|
// 【新增】扫描线颜色配置
|
|
|
- timeLineColor: { type: String, default: '#FF9800' }
|
|
|
+ timeLineColor: { type: String, default: '#FFD54F' }
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
scrollTimer: null,
|
|
|
currentViewTime: 0,
|
|
|
- // 【新增】控制扫描线的状态
|
|
|
timeLineTimer: null,
|
|
|
- currentTimeIndicator: 0
|
|
|
+ currentTimeIndicator: Math.random() * this.viewWindow,
|
|
|
+ // 每条绿波带的速度(初始固定,扫描线经过后定格)
|
|
|
+ waveSpeeds: [],
|
|
|
+ // 当前扫描线命中的所有绿波带索引
|
|
|
+ activeWaveIndices: []
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -42,7 +45,10 @@ export default {
|
|
|
return max;
|
|
|
},
|
|
|
echartsWaveData() {
|
|
|
- return this.waveData.map(w => [w.yBottom, w.yTop, w.xBL, w.xBR, w.xTL, w.xTR, w.label || '', w.direction || 'up']);
|
|
|
+ return this.waveData.map((w, i) => {
|
|
|
+ const spd = this.waveSpeeds[i] || 50;
|
|
|
+ return [w.yBottom, w.yTop, w.xBL, w.xBR, w.xTL, w.xTR, spd + 'km/h', w.direction || 'up'];
|
|
|
+ });
|
|
|
},
|
|
|
echartsGreenData() { return this.greenData.map(g => [g.y, g.start, g.end]); },
|
|
|
echartsRedData() { return this.distances.map(y => [y]); },
|
|
|
@@ -62,12 +68,21 @@ export default {
|
|
|
this.stopTimeLine();
|
|
|
},
|
|
|
watch: {
|
|
|
- waveData() { this.updateChart(); },
|
|
|
+ waveData() {
|
|
|
+ this.initWaveSpeeds();
|
|
|
+ this.updateChart();
|
|
|
+ },
|
|
|
greenData() { this.updateChart(); },
|
|
|
autoScroll(val) { val ? this.startScroll() : this.stopScroll(); }
|
|
|
},
|
|
|
methods: {
|
|
|
+ // 为每条绿波带生成初始固定速度
|
|
|
+ initWaveSpeeds() {
|
|
|
+ this.waveSpeeds = this.waveData.map(w => w.speed || (45 + Math.round(Math.random() * 10)));
|
|
|
+ },
|
|
|
+
|
|
|
initChart() {
|
|
|
+ this.initWaveSpeeds();
|
|
|
this.$_chart = echarts.init(this.$refs.chartContainer);
|
|
|
this.updateChart();
|
|
|
},
|
|
|
@@ -240,42 +255,83 @@ export default {
|
|
|
},
|
|
|
style: {
|
|
|
stroke: this.timeLineColor, // 线条颜色
|
|
|
- lineWidth: px2echarts(2), // 线条粗细
|
|
|
+ lineWidth: px2echarts(5), // 线条粗细
|
|
|
lineDash: [px2echarts(5), px2echarts(5)] // 设置为虚线,如果想实线可以删掉这行
|
|
|
}
|
|
|
};
|
|
|
},
|
|
|
|
|
|
- // 【新增】启动扫描线动画
|
|
|
+ // 启动扫描线动画(在 viewWindow 内循环,经过绿波带时速度缓慢波动)
|
|
|
startTimeLine() {
|
|
|
this.stopTimeLine();
|
|
|
let lastTime = Date.now();
|
|
|
-
|
|
|
+ let elapsed = 0;
|
|
|
+ // 控制速度变化节奏:每隔一段时间才变一次
|
|
|
+ let speedChangeTimer = 0;
|
|
|
+
|
|
|
this.timeLineTimer = setInterval(() => {
|
|
|
const now = Date.now();
|
|
|
- // 计算两次执行的时间差,转换为秒 (真实时间的 1秒 等于 X轴的 1个单位)
|
|
|
- const delta = (now - lastTime) / 1000;
|
|
|
+ const delta = (now - lastTime) / 1000;
|
|
|
lastTime = now;
|
|
|
+ elapsed += delta;
|
|
|
+ speedChangeTimer += delta;
|
|
|
|
|
|
this.currentTimeIndicator += delta;
|
|
|
-
|
|
|
- // 判定周期(当横坐标到达最大数据时间或者当前视窗的最大值时,回到原点)
|
|
|
- const cycleLimit = this.maxDataTime > 0 ? this.maxDataTime : this.viewWindow;
|
|
|
|
|
|
- if (this.currentTimeIndicator > cycleLimit) {
|
|
|
+ // 在 viewWindow 范围内循环,循环时重置所有速度
|
|
|
+ if (this.currentTimeIndicator > this.viewWindow) {
|
|
|
this.currentTimeIndicator = 0;
|
|
|
+ this.initWaveSpeeds();
|
|
|
}
|
|
|
|
|
|
- if (this.$_chart) {
|
|
|
- // 精准更新:只传入对应 id 的系列数据,避免整个图表重绘引发卡顿
|
|
|
- this.$_chart.setOption({
|
|
|
- series: [{
|
|
|
- id: 'timeLineSeries',
|
|
|
- data: [[this.currentTimeIndicator]]
|
|
|
- }]
|
|
|
+ // 检测扫描线命中的所有绿波带(支持重叠)
|
|
|
+ const x = this.currentTimeIndicator;
|
|
|
+ const hitIndices = [];
|
|
|
+ for (let i = 0; i < this.waveData.length; i++) {
|
|
|
+ const w = this.waveData[i];
|
|
|
+ const xMin = Math.min(w.xBL, w.xTL);
|
|
|
+ const xMax = Math.max(w.xBR, w.xTR);
|
|
|
+ if (x >= xMin && x <= xMax) {
|
|
|
+ hitIndices.push(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const prevIndices = this.activeWaveIndices;
|
|
|
+ this.activeWaveIndices = hitIndices;
|
|
|
+
|
|
|
+ // 扫描线在绿波带内时,每0.8秒缓慢变化所有命中带的速度
|
|
|
+ let needFullUpdate = false;
|
|
|
+ if (hitIndices.length > 0 && speedChangeTimer >= 0.8) {
|
|
|
+ speedChangeTimer = 0;
|
|
|
+ hitIndices.forEach(idx => {
|
|
|
+ const cur = this.waveSpeeds[idx] || 50;
|
|
|
+ const change = Math.round((Math.random() - 0.5) * 4);
|
|
|
+ this.$set(this.waveSpeeds, idx, Math.max(45, Math.min(55, cur + change)));
|
|
|
});
|
|
|
+ needFullUpdate = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 命中集合变化时也需要刷新
|
|
|
+ if (hitIndices.length !== prevIndices.length ||
|
|
|
+ hitIndices.some((v, i) => v !== prevIndices[i])) {
|
|
|
+ needFullUpdate = true;
|
|
|
}
|
|
|
- }, 16); // ~60fps 的刷新率,保证视觉极其平滑
|
|
|
+
|
|
|
+ if (this.$_chart) {
|
|
|
+ if (needFullUpdate) {
|
|
|
+ this.$_chart.setOption({
|
|
|
+ series: [
|
|
|
+ { id: 'waveSeries', data: this.echartsWaveData },
|
|
|
+ { id: 'timeLineSeries', data: [[this.currentTimeIndicator]] }
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.$_chart.setOption({
|
|
|
+ series: [{ id: 'timeLineSeries', data: [[this.currentTimeIndicator]] }]
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 16);
|
|
|
},
|
|
|
|
|
|
// 【新增】停止扫描线动画
|