fix: scroll speed matches mouse + CC flicker useLayoutEffect

This commit is contained in:
2026-07-26 10:26:00 +07:00
parent 7107a0cc14
commit 0b7dd82407
3 changed files with 18 additions and 8 deletions
+10 -6
View File
@@ -4888,7 +4888,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
}
}, [notes, snapVal, rollZoom, selectedNoteIds, selectionMarquee, st.currentTime, bpm, viewWidth, viewBeats, recordingState, recTempMidiNotes]);
React.useEffect(() => {
React.useLayoutEffect(() => {
const canvas = ccCanvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
@@ -5243,25 +5243,29 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
const visTop = container.scrollTop;
const visBot = visTop + container.clientHeight;
const pitchPixel = (127 - snappedPitch) * NoteHeight;
const pitchThreshold = NoteHeight * 6;
if (pitchPixel < visTop + pitchThreshold) {
const safeMargin = NoteHeight * 2;
if (pitchPixel < visTop + safeMargin) {
const target = Math.max(0, pitchPixel - safeMargin);
if (container.scrollTop !== target) container.scrollTop = target;
if (!brushAutoScrollRef.current || brushAutoScrollRef.current.direction !== 'up') {
if (brushAutoScrollRef.current) clearInterval(brushAutoScrollRef.current.id);
brushAutoScrollRef.current = {
direction: 'up',
id: setInterval(() => {
if (gridScrollRef.current) gridScrollRef.current.scrollTop = Math.max(0, gridScrollRef.current.scrollTop - Math.max(1, Math.floor(NoteHeight * 0.5)));
}, 30)
}, 16)
};
}
} else if (pitchPixel + NoteHeight > visBot - pitchThreshold) {
} else if (pitchPixel + NoteHeight > visBot - safeMargin) {
const target = Math.min(container.scrollHeight - container.clientHeight, pitchPixel - container.clientHeight + safeMargin + NoteHeight);
if (container.scrollTop !== target) container.scrollTop = target;
if (!brushAutoScrollRef.current || brushAutoScrollRef.current.direction !== 'down') {
if (brushAutoScrollRef.current) clearInterval(brushAutoScrollRef.current.id);
brushAutoScrollRef.current = {
direction: 'down',
id: setInterval(() => {
if (gridScrollRef.current) gridScrollRef.current.scrollTop = Math.min(gridScrollRef.current.scrollHeight - gridScrollRef.current.clientHeight, gridScrollRef.current.scrollTop + Math.max(1, Math.floor(NoteHeight * 0.5)));
}, 30)
}, 16)
};
}
} else {
File diff suppressed because one or more lines are too long
+6
View File
@@ -174,3 +174,9 @@
- **Tóm tắt thay đổi:** (1) Separate onMouseLeave from onMouseUp for grid canvas — preserve marquee when mouse leaves canvas. (2) Add MIDI note rescheduling on piano roll loop restart — 2nd+ loop iteration now plays sound. (3) Tempo bar drag already uses document-level listeners — works across columns.
- **Các file ảnh hưởng:** `app/static/js/app.precompiled.js`
---
### [2026-07-26 10:24] Task: Fix scroll speed match mouse + CC flicker useLayoutEffect
- **Tóm tắt thay đổi:** (1) Brush auto-scroll: thêm direct scroll target — mỗi mousemove tính pitchPixel, nếu gần rìa visible area (2 note margin) thì scroll trực tiếp tới target để tốc độ cuộn = tốc độ chuột. Giữ interval 16ms fallback cho trường hợp chuột ở rìa viewport. (2) CC flicker: đổi `React.useEffect``React.useLayoutEffect` cho CC canvas rendering effect — canvas paint trước browser paint, loại bỏ flash khi state thay đổi.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`
- **Ghi chú/Test (nếu có):** `npm run build` pass. Direct scroll target: `container.scrollTop = target` trên mỗi mousemove khi pitch ở gần rìa.
---