mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
fix: scrollbar rendering and improve dragging (#9417)
* fix: scrollbar rendering and improve dragging * tweak offsets
This commit is contained in:
parent
5fc13e4309
commit
8fb2f70414
3 changed files with 60 additions and 23 deletions
|
@ -8787,7 +8787,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const x = event.clientX;
|
const x = event.clientX;
|
||||||
const dx = x - pointerDownState.lastCoords.x;
|
const dx = x - pointerDownState.lastCoords.x;
|
||||||
this.translateCanvas({
|
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;
|
pointerDownState.lastCoords.x = x;
|
||||||
return true;
|
return true;
|
||||||
|
@ -8797,7 +8800,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const y = event.clientY;
|
const y = event.clientY;
|
||||||
const dy = y - pointerDownState.lastCoords.y;
|
const dy = y - pointerDownState.lastCoords.y;
|
||||||
this.translateCanvas({
|
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;
|
pointerDownState.lastCoords.y = y;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -11,6 +11,7 @@ export const SCROLLBAR_MARGIN = 4;
|
||||||
export const SCROLLBAR_WIDTH = 6;
|
export const SCROLLBAR_WIDTH = 6;
|
||||||
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
|
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 = (
|
export const getScrollBars = (
|
||||||
elements: RenderableElementsMap,
|
elements: RenderableElementsMap,
|
||||||
viewportWidth: number,
|
viewportWidth: number,
|
||||||
|
@ -31,9 +32,6 @@ export const getScrollBars = (
|
||||||
const viewportWidthWithZoom = viewportWidth / appState.zoom.value;
|
const viewportWidthWithZoom = viewportWidth / appState.zoom.value;
|
||||||
const viewportHeightWithZoom = viewportHeight / appState.zoom.value;
|
const viewportHeightWithZoom = viewportHeight / appState.zoom.value;
|
||||||
|
|
||||||
const viewportWidthDiff = viewportWidth - viewportWidthWithZoom;
|
|
||||||
const viewportHeightDiff = viewportHeight - viewportHeightWithZoom;
|
|
||||||
|
|
||||||
const safeArea = {
|
const safeArea = {
|
||||||
top: parseInt(getGlobalCSSVariable("sat")) || 0,
|
top: parseInt(getGlobalCSSVariable("sat")) || 0,
|
||||||
bottom: parseInt(getGlobalCSSVariable("sab")) || 0,
|
bottom: parseInt(getGlobalCSSVariable("sab")) || 0,
|
||||||
|
@ -44,10 +42,8 @@ export const getScrollBars = (
|
||||||
const isRTL = getLanguage().rtl;
|
const isRTL = getLanguage().rtl;
|
||||||
|
|
||||||
// The viewport is the rectangle currently visible for the user
|
// The viewport is the rectangle currently visible for the user
|
||||||
const viewportMinX =
|
const viewportMinX = -appState.scrollX + safeArea.left;
|
||||||
-appState.scrollX + viewportWidthDiff / 2 + safeArea.left;
|
const viewportMinY = -appState.scrollY + safeArea.top;
|
||||||
const viewportMinY =
|
|
||||||
-appState.scrollY + viewportHeightDiff / 2 + safeArea.top;
|
|
||||||
const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
|
const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
|
||||||
const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
|
const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
|
||||||
|
|
||||||
|
@ -57,8 +53,43 @@ export const getScrollBars = (
|
||||||
const sceneMaxX = Math.max(elementsMaxX, viewportMaxX);
|
const sceneMaxX = Math.max(elementsMaxX, viewportMaxX);
|
||||||
const sceneMaxY = Math.max(elementsMaxY, viewportMaxY);
|
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 {
|
return {
|
||||||
horizontal:
|
horizontal:
|
||||||
viewportMinX === sceneMinX && viewportMaxX === sceneMaxX
|
viewportMinX === sceneMinX && viewportMaxX === sceneMaxX
|
||||||
|
@ -66,18 +97,17 @@ export const getScrollBars = (
|
||||||
: {
|
: {
|
||||||
x:
|
x:
|
||||||
Math.max(safeArea.left, SCROLLBAR_MARGIN) +
|
Math.max(safeArea.left, SCROLLBAR_MARGIN) +
|
||||||
((viewportMinX - sceneMinX) / (sceneMaxX - sceneMinX)) *
|
SCROLLBAR_WIDTH +
|
||||||
viewportWidth,
|
((viewportMinX - sceneMinX) / extendedSceneWidth) * viewportWidth,
|
||||||
y:
|
y:
|
||||||
viewportHeight -
|
viewportHeight -
|
||||||
SCROLLBAR_WIDTH -
|
SCROLLBAR_WIDTH -
|
||||||
Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
|
Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
|
||||||
width:
|
width: scrollbarWidth,
|
||||||
((viewportMaxX - viewportMinX) / (sceneMaxX - sceneMinX)) *
|
|
||||||
viewportWidth -
|
|
||||||
Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right),
|
|
||||||
height: SCROLLBAR_WIDTH,
|
height: SCROLLBAR_WIDTH,
|
||||||
|
deltaMultiplier: horizontalDeltaMultiplier,
|
||||||
},
|
},
|
||||||
|
|
||||||
vertical:
|
vertical:
|
||||||
viewportMinY === sceneMinY && viewportMaxY === sceneMaxY
|
viewportMinY === sceneMinY && viewportMaxY === sceneMaxY
|
||||||
? null
|
? null
|
||||||
|
@ -88,14 +118,13 @@ export const getScrollBars = (
|
||||||
SCROLLBAR_WIDTH -
|
SCROLLBAR_WIDTH -
|
||||||
Math.max(safeArea.right, SCROLLBAR_MARGIN),
|
Math.max(safeArea.right, SCROLLBAR_MARGIN),
|
||||||
y:
|
y:
|
||||||
((viewportMinY - sceneMinY) / (sceneMaxY - sceneMinY)) *
|
Math.max(safeArea.top, SCROLLBAR_MARGIN) +
|
||||||
viewportHeight +
|
SCROLLBAR_WIDTH +
|
||||||
Math.max(safeArea.top, SCROLLBAR_MARGIN),
|
((viewportMinY - sceneMinY) / extendedSceneHeight) *
|
||||||
|
viewportHeight,
|
||||||
width: SCROLLBAR_WIDTH,
|
width: SCROLLBAR_WIDTH,
|
||||||
height:
|
height: scrollbarHeight,
|
||||||
((viewportMaxY - viewportMinY) / (sceneMaxY - sceneMinY)) *
|
deltaMultiplier: verticalDeltaMultiplier,
|
||||||
viewportHeight -
|
|
||||||
Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -130,12 +130,14 @@ export type ScrollBars = {
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
deltaMultiplier: number;
|
||||||
} | null;
|
} | null;
|
||||||
vertical: {
|
vertical: {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
deltaMultiplier: number;
|
||||||
} | null;
|
} | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue