fix: WaveformLane grid now matches TempoTrackLane bar:beat structure, bar:beat always shown on tempo lane

This commit is contained in:
2026-07-25 10:05:40 +07:00
parent 52ecc38e13
commit 6822f5ed33
+24 -29
View File
@@ -443,26 +443,28 @@ const WaveformLane = ({
const PADDING_LEFT = barDuration; // 1-bar margin on left const PADDING_LEFT = barDuration; // 1-bar margin on left
const tStart = scrollLeftVal / zoom - PADDING_LEFT; const tStart = scrollLeftVal / zoom - PADDING_LEFT;
const tEnd = (scrollLeftVal + drawWidth) / zoom + PADDING_LEFT; const tEnd = (scrollLeftVal + drawWidth) / zoom + PADDING_LEFT;
let gridSpacing = 1.0; const firstBeat = Math.floor(tStart / beatDuration) * beatDuration;
let snapDivisor = 1;
if (snapValue && snapValue !== 'free') { if (snapValue && snapValue !== 'free') {
const beatDuration = 60 / parseFloat(bpm || 120); if (snapValue === '4') snapDivisor = 4; else if (snapValue === '1') snapDivisor = 1; else if (snapValue === '1/2') snapDivisor = 0.5; else if (snapValue === '1/4') snapDivisor = 0.25; else if (snapValue === '1/8') snapDivisor = 0.125; else if (snapValue === '1/16') snapDivisor = 0.0625; else if (snapValue === '1/32') snapDivisor = 0.03125;
let divisor = 1;
if (snapValue === '4') divisor = 4; else if (snapValue === '1') divisor = 1; else if (snapValue === '1/2') divisor = 0.5; else if (snapValue === '1/4') divisor = 0.25; else if (snapValue === '1/8') divisor = 0.125; else if (snapValue === '1/16') divisor = 0.0625; else if (snapValue === '1/32') divisor = 0.03125;
gridSpacing = beatDuration * divisor;
} else {
gridSpacing = 60 / parseFloat(bpm || 120);
} }
let drawSpacing = gridSpacing; for (let t = firstBeat; t <= tEnd; t += beatDuration) {
while (drawSpacing * zoom < 10) { const beatNum = Math.floor(t / beatDuration) + 1;
drawSpacing *= 2; const isBar = beatNum % 4 === 1;
} const localX = (t - tStart) * zoom;
const firstGridStep = Math.floor(tStart / drawSpacing) * drawSpacing; if (localX < -200 || localX > drawWidth + 200) continue;
for (let s = firstGridStep; s <= tEnd; s += drawSpacing) { ctx.strokeStyle = isBar ? 'rgba(255, 255, 255, 0.12)' : 'rgba(255, 255, 255, 0.04)';
const localX = (s - tStart) * zoom; ctx.lineWidth = isBar ? 1.2 : 0.5;
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(localX, 0); ctx.moveTo(localX, 0);
ctx.lineTo(localX, height); ctx.lineTo(localX, height);
ctx.stroke(); ctx.stroke();
if (isBar && zoom >= 2) {
ctx.fillStyle = 'rgba(255, 255, 255, 0.15)';
ctx.font = 'bold 7px Inter, sans-serif';
ctx.textAlign = 'left';
ctx.fillText(`${Math.ceil(beatNum / 4)}`, localX + 2, 10);
}
} }
// Draw waveform lane // Draw waveform lane
@@ -1237,22 +1239,10 @@ const TempoTrackLane = ({
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'; ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.font = 'bold 9px Inter, sans-serif'; ctx.font = 'bold 9px Inter, sans-serif';
ctx.textAlign = 'left'; ctx.textAlign = 'left';
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.font = 'bold 9px Inter, sans-serif';
ctx.textAlign = 'left';
ctx.fillText(`${Math.ceil(beatNum / 4)}`, localX + 3, 11); ctx.fillText(`${Math.ceil(beatNum / 4)}`, localX + 3, 11);
} else if (zoom >= 2) {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.08)';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(localX, 0);
ctx.lineTo(localX, height);
ctx.stroke();
if (zoom >= 5) {
ctx.fillStyle = 'rgba(255, 255, 255, 0.4)';
ctx.font = '8px Inter, sans-serif';
ctx.textAlign = 'left';
const bar = Math.ceil(beatNum / 4);
const beat = ((beatNum - 1) % 4) + 1;
ctx.fillText(`${bar}:${beat}`, localX + 2, 9);
}
} else { } else {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.08)'; ctx.strokeStyle = 'rgba(255, 255, 255, 0.08)';
ctx.lineWidth = 1; ctx.lineWidth = 1;
@@ -1261,6 +1251,11 @@ const TempoTrackLane = ({
ctx.lineTo(localX, height); ctx.lineTo(localX, height);
ctx.stroke(); ctx.stroke();
} }
ctx.fillStyle = 'rgba(255, 255, 255, 0.35)';
ctx.font = '7px Inter, sans-serif';
const bar = Math.ceil(beatNum / 4);
const beat = ((beatNum - 1) % 4) + 1;
ctx.fillText(`${bar}:${beat}`, localX + 2, height - 3);
} }
// Draw snap sub-ticks at the bottom // Draw snap sub-ticks at the bottom