-
+
+
+
+
+
+
+ {
+ setOpen(false)
+ }}
+ />
+
+
+
+
+
+
diff --git a/components/map-component.tsx b/components/map-component.tsx
index 6d7c1f7..6e5d31a 100644
--- a/components/map-component.tsx
+++ b/components/map-component.tsx
@@ -44,7 +44,7 @@ export function MapComponent({
const [currentColorMapType, setCurrentColorMapType] = useState(colorMapType)
// 拖动状态
- const [colorbarPosition, setColorbarPosition] = useState({ x: 16, y: 16 }) // 从右边和下边的距离
+ const [colorbarPosition, setColorbarPosition] = useState({ x: 16, y: 36 }) // 从右边和下边的距离
const [isDragging, setIsDragging] = useState(false)
// 使用ref来避免频繁的状态更新
diff --git a/lib/timeline.ts b/lib/timeline.ts
index 9bfe795..4be23f8 100644
--- a/lib/timeline.ts
+++ b/lib/timeline.ts
@@ -583,6 +583,9 @@ class RealTimeTimeline {
private config: Required;
private animationFrameId: number | null = null;
private currentTimeUpdateInterval: number | null = null;
+ private mousePosition: { x: number; y: number } | null = null;
+ private showMouseIndicator: boolean = false;
+ private pendingRender: boolean = false;
constructor(canvas: HTMLCanvasElement, config?: TimelineConfig) {
this.canvas = canvas;
@@ -690,17 +693,19 @@ class RealTimeTimeline {
// 鼠标移动
this.canvas.addEventListener('mousemove', (e) => {
- if (e.button === 0) {
- const rect = this.canvas.getBoundingClientRect();
- const x = e.clientX - rect.left;
- const y = e.clientY - rect.top;
- this.interaction.handleMouseMove(x, y, this.viewport);
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
- if (this.interaction.getIsDragging()) {
- this.render();
- }
- }
+ // 更新鼠标位置并显示指示线
+ this.mousePosition = { x, y };
+ this.showMouseIndicator = true;
+ // 处理拖拽逻辑
+ this.interaction.handleMouseMove(x, y, this.viewport);
+
+ // 使用节流渲染以优化性能
+ this.requestRender();
});
// 鼠标释放
@@ -717,6 +722,8 @@ class RealTimeTimeline {
this.canvas.addEventListener('mouseleave', () => {
this.interaction.endDrag();
this.canvas.style.cursor = 'crosshair';
+ this.showMouseIndicator = false;
+ this.requestRender(); // 重新渲染以隐藏鼠标指示线
});
this.canvas.addEventListener('mouseup', (e) => {
@@ -779,6 +786,17 @@ class RealTimeTimeline {
}, 1000); // 每秒更新一次
}
+ /** 请求渲染(使用 requestAnimationFrame 节流) */
+ private requestRender(): void {
+ if (!this.pendingRender) {
+ this.pendingRender = true;
+ requestAnimationFrame(() => {
+ this.render();
+ this.pendingRender = false;
+ });
+ }
+ }
+
/** 渲染时间轴 */
render(): void {
const width = this.viewport.getWidth();
@@ -810,6 +828,9 @@ class RealTimeTimeline {
// 绘制时间标记
this.drawTimeMarks();
+
+ // 绘制鼠标位置指示线
+ this.drawMouseIndicator();
}
private changeTime(date: Date): void {
@@ -920,31 +941,59 @@ class RealTimeTimeline {
if (x >= 0 && x <= this.viewport.getWidth()) {
const height = this.viewport.getHeight();
+ const currentTimeColor = this.config.colors.currentTime ?? '#ff4444';
- // 绘制时间线
- this.ctx.strokeStyle = this.config.colors.currentTime ?? '#ff4444';
- this.ctx.lineWidth = 1;
- this.ctx.setLineDash([5, 5]);
+ this.ctx.save();
+
+ // 绘制毛玻璃背景条带
+ const backgroundWidth = 14;
+ const gradient = this.ctx.createLinearGradient(x - backgroundWidth / 2, 0, x + backgroundWidth / 2, 0);
+ // 使用当前时间颜色的红色调
+ gradient.addColorStop(0, `rgba(255, 68, 68, 0.02)`);
+ gradient.addColorStop(0.5, `rgba(255, 68, 68, 0.18)`);
+ gradient.addColorStop(1, `rgba(255, 68, 68, 0.02)`);
+
+ this.ctx.fillStyle = gradient;
+ this.ctx.fillRect(x - backgroundWidth / 2, 0, backgroundWidth, height);
+
+ // 绘制外层辉光效果
+ this.ctx.shadowColor = `rgba(255, 68, 68, 0.7)`;
+ this.ctx.shadowBlur = 10;
+ this.ctx.shadowOffsetX = 0;
+ this.ctx.shadowOffsetY = 0;
+
+ // 绘制主指示线(实线)
+ this.ctx.strokeStyle = `rgba(255, 68, 68, 0.95)`;
+ this.ctx.lineWidth = 2.5;
this.ctx.beginPath();
this.ctx.moveTo(x, 0);
this.ctx.lineTo(x, height);
this.ctx.stroke();
- this.ctx.setLineDash([]);
- // 绘制时间标签背景
+ // 重置阴影,绘制内层亮线增强辉光效果
+ this.ctx.shadowBlur = 0;
+ this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)';
+ this.ctx.lineWidth = 1;
+ this.ctx.beginPath();
+ this.ctx.moveTo(x, 0);
+ this.ctx.lineTo(x, height);
+ this.ctx.stroke();
+
+ this.ctx.restore();
+
+ // 绘制时间标签(可选,目前被注释掉)
const timeStr = TimeUtils.format(new Date(now), 'HH:mm:ss');
this.ctx.font = `bold ${this.config.sizes.primaryFontSize ?? 13}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
const metrics = this.ctx.measureText(timeStr);
const labelWidth = metrics.width + 10;
const labelHeight = 20;
- this.ctx.fillStyle = this.config.colors.currentTime ?? '#ff4444';
+ // this.ctx.fillStyle = currentTimeColor;
// this.ctx.fillRect(x - labelWidth / 2, 0, labelWidth, labelHeight);
- // 绘制时间文本
- this.ctx.fillStyle = '#ffffff';
- this.ctx.textAlign = 'center';
- this.ctx.textBaseline = 'middle';
+ // this.ctx.fillStyle = '#ffffff';
+ // this.ctx.textAlign = 'center';
+ // this.ctx.textBaseline = 'middle';
// this.ctx.fillText(timeStr, x, labelHeight / 2);
}
}
@@ -995,6 +1044,56 @@ class RealTimeTimeline {
});
}
+ /** 绘制鼠标位置指示线 */
+ private drawMouseIndicator(): void {
+ if (!this.showMouseIndicator || !this.mousePosition) {
+ return;
+ }
+
+ const height = this.viewport.getHeight();
+ const x = this.mousePosition.x;
+
+ // 确保指示线在画布范围内
+ if (x >= 0 && x <= this.viewport.getWidth()) {
+ this.ctx.save();
+
+ // 绘制毛玻璃背景条带
+ const backgroundWidth = 12;
+ const gradient = this.ctx.createLinearGradient(x - backgroundWidth / 2, 0, x + backgroundWidth / 2, 0);
+ gradient.addColorStop(0, 'rgba(135, 206, 235, 0.02)');
+ gradient.addColorStop(0.5, 'rgba(135, 206, 235, 0.15)');
+ gradient.addColorStop(1, 'rgba(135, 206, 235, 0.02)');
+
+ this.ctx.fillStyle = gradient;
+ this.ctx.fillRect(x - backgroundWidth / 2, 0, backgroundWidth, height);
+
+ // 绘制外层辉光效果
+ this.ctx.shadowColor = 'rgba(135, 206, 235, 0.6)';
+ this.ctx.shadowBlur = 8;
+ this.ctx.shadowOffsetX = 0;
+ this.ctx.shadowOffsetY = 0;
+
+ // 绘制主指示线(实线)
+ this.ctx.strokeStyle = 'rgba(135, 206, 235, 0.9)';
+ this.ctx.lineWidth = 2;
+ this.ctx.beginPath();
+ this.ctx.moveTo(x, 0);
+ this.ctx.lineTo(x, height);
+ this.ctx.stroke();
+
+ // 重置阴影,绘制内层亮线增强辉光效果
+ this.ctx.shadowBlur = 0;
+ this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
+ this.ctx.lineWidth = 1;
+ this.ctx.beginPath();
+ this.ctx.moveTo(x, 0);
+ this.ctx.lineTo(x, height);
+ this.ctx.stroke();
+
+ this.ctx.restore();
+ }
+ }
+
/** 获取当前视口信息 */