2020-01-06 20:24:54 +04:00
|
|
|
import { ExcalidrawElement } from "../element/types";
|
2020-01-26 20:15:08 +01:00
|
|
|
import { getCommonBounds } from "../element";
|
2020-02-19 08:25:01 -08:00
|
|
|
import { FlooredNumber } from "../types";
|
2020-01-06 20:24:54 +04:00
|
|
|
|
|
|
|
const SCROLLBAR_MARGIN = 4;
|
|
|
|
export const SCROLLBAR_WIDTH = 6;
|
|
|
|
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
|
|
|
|
|
|
|
|
export function getScrollBars(
|
2020-01-09 19:22:04 +04:00
|
|
|
elements: readonly ExcalidrawElement[],
|
2020-02-08 16:20:14 -08:00
|
|
|
viewportWidth: number,
|
|
|
|
viewportHeight: number,
|
2020-02-15 21:03:32 +01:00
|
|
|
{
|
|
|
|
scrollX,
|
|
|
|
scrollY,
|
|
|
|
zoom,
|
|
|
|
}: {
|
2020-02-19 08:25:01 -08:00
|
|
|
scrollX: FlooredNumber;
|
|
|
|
scrollY: FlooredNumber;
|
2020-02-15 21:03:32 +01:00
|
|
|
zoom: number;
|
|
|
|
},
|
2020-01-06 20:24:54 +04:00
|
|
|
) {
|
2020-02-08 16:20:14 -08:00
|
|
|
// This is the bounding box of all the elements
|
|
|
|
const [
|
|
|
|
elementsMinX,
|
|
|
|
elementsMinY,
|
|
|
|
elementsMaxX,
|
|
|
|
elementsMaxY,
|
|
|
|
] = getCommonBounds(elements);
|
2020-01-06 20:24:54 +04:00
|
|
|
|
2020-02-15 21:03:32 +01:00
|
|
|
// Apply zoom
|
|
|
|
const viewportWidthWithZoom = viewportWidth / zoom;
|
|
|
|
const viewportHeightWithZoom = viewportHeight / zoom;
|
|
|
|
|
|
|
|
const viewportWidthDiff = viewportWidth - viewportWidthWithZoom;
|
|
|
|
const viewportHeightDiff = viewportHeight - viewportHeightWithZoom;
|
|
|
|
|
2020-02-08 16:20:14 -08:00
|
|
|
// The viewport is the rectangle currently visible for the user
|
2020-02-15 21:03:32 +01:00
|
|
|
const viewportMinX = -scrollX + viewportWidthDiff / 2;
|
|
|
|
const viewportMinY = -scrollY + viewportHeightDiff / 2;
|
|
|
|
const viewportMaxX = viewportMinX + viewportWidthWithZoom;
|
|
|
|
const viewportMaxY = viewportMinY + viewportHeightWithZoom;
|
2020-01-26 20:15:08 +01:00
|
|
|
|
2020-02-08 16:20:14 -08:00
|
|
|
// 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);
|
2020-01-06 20:24:54 +04:00
|
|
|
|
2020-02-08 16:20:14 -08:00
|
|
|
// The scrollbar represents where the viewport is in relationship to the scene
|
2020-01-06 20:24:54 +04:00
|
|
|
|
|
|
|
return {
|
2020-02-08 16:20:14 -08:00
|
|
|
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,
|
|
|
|
},
|
2020-01-06 20:24:54 +04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isOverScrollBars(
|
2020-01-09 19:22:04 +04:00
|
|
|
elements: readonly ExcalidrawElement[],
|
2020-01-06 20:24:54 +04:00
|
|
|
x: number,
|
|
|
|
y: number,
|
2020-02-08 16:20:14 -08:00
|
|
|
viewportWidth: number,
|
|
|
|
viewportHeight: number,
|
2020-02-15 21:03:32 +01:00
|
|
|
{
|
|
|
|
scrollX,
|
|
|
|
scrollY,
|
|
|
|
zoom,
|
|
|
|
}: {
|
2020-02-19 08:25:01 -08:00
|
|
|
scrollX: FlooredNumber;
|
|
|
|
scrollY: FlooredNumber;
|
2020-02-15 21:03:32 +01:00
|
|
|
zoom: number;
|
|
|
|
},
|
2020-01-06 20:24:54 +04:00
|
|
|
) {
|
2020-02-15 21:03:32 +01:00
|
|
|
const scrollBars = getScrollBars(elements, viewportWidth, viewportHeight, {
|
2020-01-06 20:24:54 +04:00
|
|
|
scrollX,
|
2020-01-24 12:04:54 +02:00
|
|
|
scrollY,
|
2020-02-15 21:03:32 +01:00
|
|
|
zoom,
|
|
|
|
});
|
2020-01-06 20:24:54 +04:00
|
|
|
|
|
|
|
const [isOverHorizontalScrollBar, isOverVerticalScrollBar] = [
|
|
|
|
scrollBars.horizontal,
|
2020-01-24 12:04:54 +02:00
|
|
|
scrollBars.vertical,
|
2020-02-08 16:20:14 -08:00
|
|
|
].map(scrollBar => {
|
|
|
|
return (
|
2020-01-06 20:24:54 +04:00
|
|
|
scrollBar &&
|
|
|
|
scrollBar.x <= x &&
|
|
|
|
x <= scrollBar.x + scrollBar.width &&
|
|
|
|
scrollBar.y <= y &&
|
2020-02-08 16:20:14 -08:00
|
|
|
y <= scrollBar.y + scrollBar.height
|
|
|
|
);
|
|
|
|
});
|
2020-01-06 20:24:54 +04:00
|
|
|
|
|
|
|
return {
|
|
|
|
isOverHorizontalScrollBar,
|
2020-01-24 12:04:54 +02:00
|
|
|
isOverVerticalScrollBar,
|
2020-01-06 20:24:54 +04:00
|
|
|
};
|
|
|
|
}
|