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-03-01 21:43:35 +01:00
|
|
|
import { ScrollBars } from "./types";
|
2020-03-18 11:31:40 -04:00
|
|
|
import { getGlobalCSSVariable } from "../utils";
|
2020-01-06 20:24:54 +04:00
|
|
|
|
2020-03-18 11:31:40 -04:00
|
|
|
export const SCROLLBAR_MARGIN = 4;
|
2020-01-06 20:24:54 +04:00
|
|
|
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-03-01 21:43:35 +01:00
|
|
|
): ScrollBars {
|
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-03-18 11:31:40 -04:00
|
|
|
const safeArea = {
|
|
|
|
top: parseInt(getGlobalCSSVariable("sat")),
|
|
|
|
bottom: parseInt(getGlobalCSSVariable("sab")),
|
|
|
|
left: parseInt(getGlobalCSSVariable("sal")),
|
|
|
|
right: parseInt(getGlobalCSSVariable("sar")),
|
|
|
|
};
|
|
|
|
|
2020-02-08 16:20:14 -08:00
|
|
|
// The viewport is the rectangle currently visible for the user
|
2020-03-18 11:31:40 -04:00
|
|
|
const viewportMinX = -scrollX + viewportWidthDiff / 2 + safeArea.left;
|
|
|
|
const viewportMinY = -scrollY + viewportHeightDiff / 2 + safeArea.top;
|
|
|
|
const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
|
|
|
|
const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
|
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:
|
2020-03-18 11:31:40 -04:00
|
|
|
Math.max(safeArea.left, SCROLLBAR_MARGIN) +
|
2020-02-08 16:20:14 -08:00
|
|
|
((viewportMinX - sceneMinX) / (sceneMaxX - sceneMinX)) *
|
2020-03-18 11:31:40 -04:00
|
|
|
viewportWidth,
|
|
|
|
y:
|
|
|
|
viewportHeight -
|
|
|
|
SCROLLBAR_WIDTH -
|
|
|
|
Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
|
2020-02-08 16:20:14 -08:00
|
|
|
width:
|
|
|
|
((viewportMaxX - viewportMinX) / (sceneMaxX - sceneMinX)) *
|
|
|
|
viewportWidth -
|
2020-03-18 11:31:40 -04:00
|
|
|
Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right),
|
2020-02-08 16:20:14 -08:00
|
|
|
height: SCROLLBAR_WIDTH,
|
|
|
|
},
|
|
|
|
vertical:
|
|
|
|
viewportMinY === sceneMinY && viewportMaxY === sceneMaxY
|
|
|
|
? null
|
|
|
|
: {
|
2020-03-18 11:31:40 -04:00
|
|
|
x:
|
|
|
|
viewportWidth -
|
|
|
|
SCROLLBAR_WIDTH -
|
|
|
|
Math.max(safeArea.right, SCROLLBAR_MARGIN),
|
2020-02-08 16:20:14 -08:00
|
|
|
y:
|
|
|
|
((viewportMinY - sceneMinY) / (sceneMaxY - sceneMinY)) *
|
|
|
|
viewportHeight +
|
2020-03-18 11:31:40 -04:00
|
|
|
Math.max(safeArea.top, SCROLLBAR_MARGIN),
|
2020-02-08 16:20:14 -08:00
|
|
|
width: SCROLLBAR_WIDTH,
|
|
|
|
height:
|
|
|
|
((viewportMaxY - viewportMinY) / (sceneMaxY - sceneMinY)) *
|
|
|
|
viewportHeight -
|
2020-03-18 11:31:40 -04:00
|
|
|
Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom),
|
2020-02-08 16:20:14 -08:00
|
|
|
},
|
2020-01-06 20:24:54 +04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-03-01 21:43:35 +01:00
|
|
|
export function isOverScrollBars(scrollBars: ScrollBars, x: number, y: number) {
|
2020-01-06 20:24:54 +04:00
|
|
|
const [isOverHorizontalScrollBar, isOverVerticalScrollBar] = [
|
|
|
|
scrollBars.horizontal,
|
2020-01-24 12:04:54 +02:00
|
|
|
scrollBars.vertical,
|
2020-03-23 13:05:07 +02:00
|
|
|
].map((scrollBar) => {
|
2020-02-08 16:20:14 -08:00
|
|
|
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
|
|
|
};
|
|
|
|
}
|