excalidraw/src/scene/scrollbars.ts
Christopher Chedeau c2a3b67ccc
Fix scrollbar (#735)
The computation was not correct. I'm not really sure how it used to work but it was not taking into account the dimensions of the scene so it was wrong.

The new algorithm is computing the scrollbar such that it's the position of the viewport in relationship to the bounding box of the viewport and all the elements.

Fixes #680
2020-02-08 16:20:14 -08:00

105 lines
2.9 KiB
TypeScript

import { ExcalidrawElement } from "../element/types";
import { getCommonBounds } from "../element";
const SCROLLBAR_MARGIN = 4;
export const SCROLLBAR_WIDTH = 6;
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
export function getScrollBars(
elements: readonly ExcalidrawElement[],
viewportWidth: number,
viewportHeight: number,
scrollX: number,
scrollY: number,
) {
// This is the bounding box of all the elements
const [
elementsMinX,
elementsMinY,
elementsMaxX,
elementsMaxY,
] = getCommonBounds(elements);
// The viewport is the rectangle currently visible for the user
const viewportMinX = -scrollX;
const viewportMinY = -scrollY;
const viewportMaxX = -scrollX + viewportWidth;
const viewportMaxY = -scrollY + viewportHeight;
// The scene is the bounding box of both the elements and viewport
const sceneMinX = Math.min(elementsMinX, viewportMinX);
const sceneMinY = Math.min(elementsMinY, viewportMinY);
const sceneMaxX = Math.max(elementsMaxX, viewportMaxX);
const sceneMaxY = Math.max(elementsMaxY, viewportMaxY);
// The scrollbar represents where the viewport is in relationship to the scene
return {
horizontal:
viewportMinX === sceneMinX && viewportMaxX === sceneMaxX
? null
: {
x:
((viewportMinX - sceneMinX) / (sceneMaxX - sceneMinX)) *
viewportWidth +
SCROLLBAR_MARGIN,
y: viewportHeight - SCROLLBAR_WIDTH - SCROLLBAR_MARGIN,
width:
((viewportMaxX - viewportMinX) / (sceneMaxX - sceneMinX)) *
viewportWidth -
SCROLLBAR_MARGIN * 2,
height: SCROLLBAR_WIDTH,
},
vertical:
viewportMinY === sceneMinY && viewportMaxY === sceneMaxY
? null
: {
x: viewportWidth - SCROLLBAR_WIDTH - SCROLLBAR_MARGIN,
y:
((viewportMinY - sceneMinY) / (sceneMaxY - sceneMinY)) *
viewportHeight +
SCROLLBAR_MARGIN,
width: SCROLLBAR_WIDTH,
height:
((viewportMaxY - viewportMinY) / (sceneMaxY - sceneMinY)) *
viewportHeight -
SCROLLBAR_MARGIN * 2,
},
};
}
export function isOverScrollBars(
elements: readonly ExcalidrawElement[],
x: number,
y: number,
viewportWidth: number,
viewportHeight: number,
scrollX: number,
scrollY: number,
) {
const scrollBars = getScrollBars(
elements,
viewportWidth,
viewportHeight,
scrollX,
scrollY,
);
const [isOverHorizontalScrollBar, isOverVerticalScrollBar] = [
scrollBars.horizontal,
scrollBars.vertical,
].map(scrollBar => {
return (
scrollBar &&
scrollBar.x <= x &&
x <= scrollBar.x + scrollBar.width &&
scrollBar.y <= y &&
y <= scrollBar.y + scrollBar.height
);
});
return {
isOverHorizontalScrollBar,
isOverVerticalScrollBar,
};
}