fix: scrollbar rendering and improve dragging (#9417)

* fix: scrollbar rendering and improve dragging

* tweak offsets
This commit is contained in:
David Luzar 2025-04-20 12:28:41 +02:00 committed by GitHub
parent 5fc13e4309
commit 8fb2f70414
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 60 additions and 23 deletions

View file

@ -8787,7 +8787,10 @@ class App extends React.Component<AppProps, AppState> {
const x = event.clientX;
const dx = x - pointerDownState.lastCoords.x;
this.translateCanvas({
scrollX: this.state.scrollX - dx / this.state.zoom.value,
scrollX:
this.state.scrollX -
(dx * (currentScrollBars.horizontal?.deltaMultiplier || 1)) /
this.state.zoom.value,
});
pointerDownState.lastCoords.x = x;
return true;
@ -8797,7 +8800,10 @@ class App extends React.Component<AppProps, AppState> {
const y = event.clientY;
const dy = y - pointerDownState.lastCoords.y;
this.translateCanvas({
scrollY: this.state.scrollY - dy / this.state.zoom.value,
scrollY:
this.state.scrollY -
(dy * (currentScrollBars.vertical?.deltaMultiplier || 1)) /
this.state.zoom.value,
});
pointerDownState.lastCoords.y = y;
return true;

View file

@ -11,6 +11,7 @@ export const SCROLLBAR_MARGIN = 4;
export const SCROLLBAR_WIDTH = 6;
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
// The scrollbar represents where the viewport is in relationship to the scene
export const getScrollBars = (
elements: RenderableElementsMap,
viewportWidth: number,
@ -31,9 +32,6 @@ export const getScrollBars = (
const viewportWidthWithZoom = viewportWidth / appState.zoom.value;
const viewportHeightWithZoom = viewportHeight / appState.zoom.value;
const viewportWidthDiff = viewportWidth - viewportWidthWithZoom;
const viewportHeightDiff = viewportHeight - viewportHeightWithZoom;
const safeArea = {
top: parseInt(getGlobalCSSVariable("sat")) || 0,
bottom: parseInt(getGlobalCSSVariable("sab")) || 0,
@ -44,10 +42,8 @@ export const getScrollBars = (
const isRTL = getLanguage().rtl;
// The viewport is the rectangle currently visible for the user
const viewportMinX =
-appState.scrollX + viewportWidthDiff / 2 + safeArea.left;
const viewportMinY =
-appState.scrollY + viewportHeightDiff / 2 + safeArea.top;
const viewportMinX = -appState.scrollX + safeArea.left;
const viewportMinY = -appState.scrollY + safeArea.top;
const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
@ -57,8 +53,43 @@ export const getScrollBars = (
const sceneMaxX = Math.max(elementsMaxX, viewportMaxX);
const sceneMaxY = Math.max(elementsMaxY, viewportMaxY);
// The scrollbar represents where the viewport is in relationship to the scene
// the elements-only bbox
const sceneWidth = elementsMaxX - elementsMinX;
const sceneHeight = elementsMaxY - elementsMinY;
// scene (elements) bbox + the viewport bbox that extends outside of it
const extendedSceneWidth = sceneMaxX - sceneMinX;
const extendedSceneHeight = sceneMaxY - sceneMinY;
const scrollWidthOffset =
Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right) +
SCROLLBAR_WIDTH * 2;
const scrollbarWidth =
viewportWidth * (viewportWidthWithZoom / extendedSceneWidth) -
scrollWidthOffset;
const scrollbarHeightOffset =
Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom) +
SCROLLBAR_WIDTH * 2;
const scrollbarHeight =
viewportHeight * (viewportHeightWithZoom / extendedSceneHeight) -
scrollbarHeightOffset;
// NOTE the delta multiplier calculation isn't quite correct when viewport
// is extended outside the scene (elements) bbox as there's some small
// accumulation error. I'll let this be an exercise for others to fix. ^^
const horizontalDeltaMultiplier =
extendedSceneWidth > sceneWidth
? (extendedSceneWidth * appState.zoom.value) /
(scrollbarWidth + scrollWidthOffset)
: viewportWidth / (scrollbarWidth + scrollWidthOffset);
const verticalDeltaMultiplier =
extendedSceneHeight > sceneHeight
? (extendedSceneHeight * appState.zoom.value) /
(scrollbarHeight + scrollbarHeightOffset)
: viewportHeight / (scrollbarHeight + scrollbarHeightOffset);
return {
horizontal:
viewportMinX === sceneMinX && viewportMaxX === sceneMaxX
@ -66,18 +97,17 @@ export const getScrollBars = (
: {
x:
Math.max(safeArea.left, SCROLLBAR_MARGIN) +
((viewportMinX - sceneMinX) / (sceneMaxX - sceneMinX)) *
viewportWidth,
SCROLLBAR_WIDTH +
((viewportMinX - sceneMinX) / extendedSceneWidth) * viewportWidth,
y:
viewportHeight -
SCROLLBAR_WIDTH -
Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
width:
((viewportMaxX - viewportMinX) / (sceneMaxX - sceneMinX)) *
viewportWidth -
Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right),
width: scrollbarWidth,
height: SCROLLBAR_WIDTH,
deltaMultiplier: horizontalDeltaMultiplier,
},
vertical:
viewportMinY === sceneMinY && viewportMaxY === sceneMaxY
? null
@ -88,14 +118,13 @@ export const getScrollBars = (
SCROLLBAR_WIDTH -
Math.max(safeArea.right, SCROLLBAR_MARGIN),
y:
((viewportMinY - sceneMinY) / (sceneMaxY - sceneMinY)) *
viewportHeight +
Math.max(safeArea.top, SCROLLBAR_MARGIN),
Math.max(safeArea.top, SCROLLBAR_MARGIN) +
SCROLLBAR_WIDTH +
((viewportMinY - sceneMinY) / extendedSceneHeight) *
viewportHeight,
width: SCROLLBAR_WIDTH,
height:
((viewportMaxY - viewportMinY) / (sceneMaxY - sceneMinY)) *
viewportHeight -
Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom),
height: scrollbarHeight,
deltaMultiplier: verticalDeltaMultiplier,
},
};
};

View file

@ -130,12 +130,14 @@ export type ScrollBars = {
y: number;
width: number;
height: number;
deltaMultiplier: number;
} | null;
vertical: {
x: number;
y: number;
width: number;
height: number;
deltaMultiplier: number;
} | null;
};