/ concept-collection / benchcompress
Sign in
concept-collection / benchcompress
benchcompress / web-ui / src / components / dataset / TimeseriesNavigationBar.tsx
98 lines · 2.6 KBCodeBlameHistory
1ac6645long descriptionsJeremy Magland 1import React, { useRef } from "react";
2import { Range } from "./WorkerTypes";
4interface TimeseriesNavigationBarProps {
5 width: number;
6 height: number;
7 totalRange: Range;
8 viewRange: Range;
9 onViewRangeChange: (range: Range) => void;
12const TimeseriesNavigationBar: React.FC<TimeseriesNavigationBarProps> = ({
13 width,
14 height,
15 totalRange,
16 viewRange,
17 onViewRangeChange,
18}) => {
19 const containerRef = useRef<HTMLDivElement>(null);
21 // Constants
22 const minMarkerWidth = 25; // Minimum width of the marker in pixels
23 const padding = 10; // Padding on left and right
24 const barWidth = width - 2 * padding;
26 // Convert data range to pixel coordinates
27 const rangeToPixel = (value: number): number => {
28 const ratio = (value - totalRange.min) / (totalRange.max - totalRange.min);
29 return padding + ratio * barWidth;
30 };
32 // Convert pixel coordinates to data range
33 const pixelToRange = (pixel: number): number => {
34 const ratio = (pixel - padding) / barWidth;
35 return totalRange.min + ratio * (totalRange.max - totalRange.min);
36 };
38 // Calculate marker position and width
39 const markerLeft = rangeToPixel(viewRange.min);
40 const rawMarkerWidth = rangeToPixel(viewRange.max) - markerLeft;
41 const markerWidth = Math.max(rawMarkerWidth, minMarkerWidth);
43 const handleClick = (e: React.MouseEvent) => {
44 if (!containerRef.current) return;
46 const rect = containerRef.current.getBoundingClientRect();
47 const clickX = e.clientX - rect.left;
49 // Click on the bar - center the view on click position
50 const clickedValue = pixelToRange(clickX);
51 const currentSize = viewRange.max - viewRange.min;
52 const halfSize = currentSize / 2;
54 let newMin = clickedValue - halfSize;
55 let newMax = clickedValue + halfSize;
57 // Clamp to total range bounds
58 if (newMin < totalRange.min) {
59 newMin = totalRange.min;
60 newMax = newMin + currentSize;
61 }
62 if (newMax > totalRange.max) {
63 newMax = totalRange.max;
64 newMin = newMax - currentSize;
65 }
67 onViewRangeChange({ min: newMin, max: newMax });
68 };
70 return (
71 <div
72 ref={containerRef}
73 style={{
74 width,
75 height,
76 position: "relative",
77 backgroundColor: "#f0f0f0",
78 borderRadius: 4,
79 cursor: "pointer",
80 }}
81 onClick={handleClick}
82 >
83 <div
84 style={{
85 position: "absolute",
86 left: markerLeft,
87 width: markerWidth,
88 height: "100%",
89 backgroundColor: "#007bff",
90 borderRadius: 4,
91 pointerEvents: "none",
92 }}
93 />
94 </div>
95 );
96};
98export default TimeseriesNavigationBar;
moveopenescclose