fix: sync TempoTrackLane leadIn with ruler, time labels to top
- Added leadInMargin prop to TempoTrackLane so time-0 aligns with ruler - Added CLIP_BUFFER to TempoTrackLane grid rendering - Moved TimelineRuler time labels from bottom (y=40) to top (y=11)
This commit is contained in:
+12
-8
@@ -1302,7 +1302,7 @@ const TimelineRuler = ({
|
||||
ctx.fillStyle = 'rgba(255, 180, 100, 0.55)';
|
||||
ctx.font = 'bold 8px monospace';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(formatTimeSimple(t), localX + 4, height - 8);
|
||||
ctx.fillText(formatTimeSimple(t), localX + 4, 11);
|
||||
}
|
||||
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.4)';
|
||||
@@ -1337,7 +1337,8 @@ const TempoTrackLane = ({
|
||||
snapValue,
|
||||
onRulerMouseDown,
|
||||
scrollLeft,
|
||||
canvasRedrawCount
|
||||
canvasRedrawCount,
|
||||
leadInMargin: propLeadIn
|
||||
}) => {
|
||||
const canvasRef = useRef(null);
|
||||
const drawWidth = Math.min(timelineWidth, viewportWidth);
|
||||
@@ -1358,15 +1359,17 @@ const TempoTrackLane = ({
|
||||
ctx.fillRect(0, 0, drawWidth, height);
|
||||
const beatDuration = 60 / bpm;
|
||||
const barDuration = beatDuration * 4;
|
||||
const leadIn = propLeadIn !== undefined ? propLeadIn : barDuration;
|
||||
const CLIP_BUFFER = Math.max(400, barDuration * zoom + 200);
|
||||
const PADDING_LEFT = barDuration; // 1-bar margin on left
|
||||
const tStart = scrollLeftVal / zoom - PADDING_LEFT;
|
||||
const tEnd = (scrollLeftVal + drawWidth) / zoom + PADDING_LEFT;
|
||||
const tStart = (scrollLeftVal - leadIn * zoom) / zoom - PADDING_LEFT;
|
||||
const tEnd = (scrollLeftVal + drawWidth - leadIn * zoom) / zoom + PADDING_LEFT;
|
||||
const firstBeat = Math.floor(tStart / beatDuration) * beatDuration;
|
||||
for (let t = firstBeat; t <= tEnd; t += beatDuration) {
|
||||
const beatNum = Math.floor(t / beatDuration) + 1;
|
||||
const isBar = beatNum % 4 === 1;
|
||||
const localX = (t - tStart) * zoom;
|
||||
if (localX < -200 || localX > drawWidth + 200) continue;
|
||||
if (localX < -CLIP_BUFFER || localX > drawWidth + CLIP_BUFFER) continue;
|
||||
if (isBar) {
|
||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
|
||||
ctx.lineWidth = 1.5;
|
||||
@@ -1423,7 +1426,7 @@ const TempoTrackLane = ({
|
||||
const firstSec = Math.floor(tStart / secInterval) * secInterval;
|
||||
for (let t = firstSec; t <= tEnd; t += secInterval) {
|
||||
const localX = (t - tStart) * zoom;
|
||||
if (localX < -200 || localX > drawWidth + 200) continue;
|
||||
if (localX < -CLIP_BUFFER || localX > drawWidth + CLIP_BUFFER) continue;
|
||||
ctx.strokeStyle = 'rgba(255, 180, 100, 0.15)';
|
||||
ctx.lineWidth = 0.8;
|
||||
ctx.beginPath();
|
||||
@@ -1440,7 +1443,7 @@ const TempoTrackLane = ({
|
||||
ctx.font = 'bold 10px Inter, sans-serif';
|
||||
ctx.textAlign = 'right';
|
||||
ctx.fillText(`${bpm} BPM`, drawWidth - 6, 12);
|
||||
}, [bpm, zoom, timelineWidth, viewportWidth, snapValue, scrollLeft, canvasRedrawCount]);
|
||||
}, [bpm, zoom, timelineWidth, viewportWidth, snapValue, scrollLeft, canvasRedrawCount, propLeadIn]);
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
||||
key: "virtual-spacer-tempo",
|
||||
style: {
|
||||
@@ -1459,7 +1462,8 @@ const TempoTrackLane = ({
|
||||
onMouseDown: e => {
|
||||
const rect = canvasRef.current.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left + (scrollLeft || 0);
|
||||
const time = Math.max(0, x / zoom);
|
||||
const leadIn = (60 / bpm) * 4;
|
||||
const time = Math.max(0, x / zoom - leadIn);
|
||||
if (e.shiftKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
Reference in New Issue
Block a user