refactor: simplify piano roll zoom - use CSS clip instead of manual grid extension

This commit is contained in:
2026-07-25 07:45:06 +07:00
parent b04a76ebfb
commit 46530c8896
2 changed files with 13 additions and 32 deletions
+8 -26
View File
@@ -4433,9 +4433,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
const rollBeatsRef = React.useRef(rollBeats); const rollBeatsRef = React.useRef(rollBeats);
rollBeatsRef.current = rollBeats; rollBeatsRef.current = rollBeats;
const totalBeats = Math.max(rollBeats, noteMaxBeat + 16, 64); // at least 64 beats (16 bars) for scrolling const totalBeats = Math.max(rollBeats, noteMaxBeat + 16, 64); // at least 64 beats (16 bars) for scrolling
const [gridViewWidth, setGridViewWidth] = React.useState(800);
const drawWidth = totalBeats * pixelsPerBeat; const drawWidth = totalBeats * pixelsPerBeat;
const cssWidth = Math.max(drawWidth, gridViewWidth);
const [notes, setNotes] = React.useState(st.notes || []); const [notes, setNotes] = React.useState(st.notes || []);
const [selectedNoteIds, setSelectedNoteIds] = React.useState([]); const [selectedNoteIds, setSelectedNoteIds] = React.useState([]);
@@ -4573,26 +4571,13 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
}; };
}, [notes, st.currentTime, pixelsPerBeat, st.id, totalBeats, bpm]); }, [notes, st.currentTime, pixelsPerBeat, st.id, totalBeats, bpm]);
// Track grid container width for zoom fill React.useEffect(() => {
React.useEffect(() => {
const el = gridScrollRef.current;
if (!el) return;
const ro = new ResizeObserver(entries => {
for (const entry of entries) setGridViewWidth(entry.contentRect.width);
});
ro.observe(el);
setGridViewWidth(el.clientWidth);
return () => ro.disconnect();
}, []);
React.useEffect(() => {
const canvas = canvasRef.current; const canvas = canvasRef.current;
if (!canvas) return; if (!canvas) return;
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1; const dpr = window.devicePixelRatio || 1;
const h = 128 * NoteHeight; const h = 128 * NoteHeight;
const canvasW = Math.max(drawWidth, gridViewWidth); canvas.width = drawWidth * dpr;
canvas.width = canvasW * dpr;
canvas.height = h * dpr; canvas.height = h * dpr;
ctx.scale(dpr, dpr); ctx.scale(dpr, dpr);
@@ -4620,9 +4605,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
else if (snapVal === '1/16') snapBeats = 0.25; else if (snapVal === '1/16') snapBeats = 0.25;
else if (snapVal === '1/32') snapBeats = 0.125; else if (snapVal === '1/32') snapBeats = 0.125;
const maxBeatPx = drawWidth; for (let beat = 0; beat <= totalBeats; beat += snapBeats) {
const gridEndBeat = Math.max(totalBeats, Math.ceil(canvasW / pixelsPerBeat) + 4);
for (let beat = 0; beat <= gridEndBeat; beat += snapBeats) {
const x = beat * pixelsPerBeat; const x = beat * pixelsPerBeat;
if (x > drawWidth) break; if (x > drawWidth) break;
const isBar = beat % timeSigNum === 0; const isBar = beat % timeSigNum === 0;
@@ -4697,7 +4680,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1; const dpr = window.devicePixelRatio || 1;
const h = 80; const h = 80;
canvas.width = Math.max(drawWidth, gridViewWidth) * dpr; canvas.width = drawWidth * dpr;
canvas.height = h * dpr; canvas.height = h * dpr;
ctx.scale(dpr, dpr); ctx.scale(dpr, dpr);
@@ -5348,8 +5331,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
const renderBarLabels = () => { const renderBarLabels = () => {
const labels = []; const labels = [];
const extraBars = Math.max(0, Math.ceil((gridViewWidth - drawWidth) / (4 * pixelsPerBeat)) + 2); const barsCount = Math.ceil(totalBeats / 4);
const barsCount = Math.ceil(totalBeats / 4) + extraBars;
for (let bar = 0; bar < barsCount; bar++) { for (let bar = 0; bar < barsCount; bar++) {
const x = bar * 4 * pixelsPerBeat; const x = bar * 4 * pixelsPerBeat;
labels.push( labels.push(
@@ -5454,7 +5436,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
} }
}, /*#__PURE__*/React.createElement("div", { }, /*#__PURE__*/React.createElement("div", {
style: { style: {
width: `${cssWidth}px`, width: `${drawWidth}px`,
height: '100%' height: '100%'
}, },
className: "relative h-full font-mono text-[9px] text-zinc-500 font-bold" className: "relative h-full font-mono text-[9px] text-zinc-500 font-bold"
@@ -5474,7 +5456,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
className: "flex-1 overflow-auto bg-[#141414] min-w-0" className: "flex-1 overflow-auto bg-[#141414] min-w-0"
}, /*#__PURE__*/React.createElement("div", { }, /*#__PURE__*/React.createElement("div", {
style: { style: {
width: `${cssWidth}px`, width: `${drawWidth}px`,
height: `${(128 - PITCH_START) * NoteHeight}px` height: `${(128 - PITCH_START) * NoteHeight}px`
}, },
className: "relative" className: "relative"
@@ -5494,7 +5476,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
className: "flex-1 overflow-x-hidden min-w-0" className: "flex-1 overflow-x-hidden min-w-0"
}, /*#__PURE__*/React.createElement("div", { }, /*#__PURE__*/React.createElement("div", {
style: { style: {
width: `${cssWidth}px`, width: `${drawWidth}px`,
height: '100%' height: '100%'
}, },
className: "relative" className: "relative"
File diff suppressed because one or more lines are too long