scrollbars.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { ExcalidrawElement } from "../element/types";
  2. import { getCommonBounds } from "../element";
  3. import { FlooredNumber } from "../types";
  4. import { ScrollBars } from "./types";
  5. import { getGlobalCSSVariable } from "../utils";
  6. export const SCROLLBAR_MARGIN = 4;
  7. export const SCROLLBAR_WIDTH = 6;
  8. export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
  9. export function getScrollBars(
  10. elements: readonly ExcalidrawElement[],
  11. viewportWidth: number,
  12. viewportHeight: number,
  13. {
  14. scrollX,
  15. scrollY,
  16. zoom,
  17. }: {
  18. scrollX: FlooredNumber;
  19. scrollY: FlooredNumber;
  20. zoom: number;
  21. },
  22. ): ScrollBars {
  23. // This is the bounding box of all the elements
  24. const [
  25. elementsMinX,
  26. elementsMinY,
  27. elementsMaxX,
  28. elementsMaxY,
  29. ] = getCommonBounds(elements);
  30. // Apply zoom
  31. const viewportWidthWithZoom = viewportWidth / zoom;
  32. const viewportHeightWithZoom = viewportHeight / zoom;
  33. const viewportWidthDiff = viewportWidth - viewportWidthWithZoom;
  34. const viewportHeightDiff = viewportHeight - viewportHeightWithZoom;
  35. const safeArea = {
  36. top: parseInt(getGlobalCSSVariable("sat")),
  37. bottom: parseInt(getGlobalCSSVariable("sab")),
  38. left: parseInt(getGlobalCSSVariable("sal")),
  39. right: parseInt(getGlobalCSSVariable("sar")),
  40. };
  41. // The viewport is the rectangle currently visible for the user
  42. const viewportMinX = -scrollX + viewportWidthDiff / 2 + safeArea.left;
  43. const viewportMinY = -scrollY + viewportHeightDiff / 2 + safeArea.top;
  44. const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
  45. const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
  46. // The scene is the bounding box of both the elements and viewport
  47. const sceneMinX = Math.min(elementsMinX, viewportMinX);
  48. const sceneMinY = Math.min(elementsMinY, viewportMinY);
  49. const sceneMaxX = Math.max(elementsMaxX, viewportMaxX);
  50. const sceneMaxY = Math.max(elementsMaxY, viewportMaxY);
  51. // The scrollbar represents where the viewport is in relationship to the scene
  52. return {
  53. horizontal:
  54. viewportMinX === sceneMinX && viewportMaxX === sceneMaxX
  55. ? null
  56. : {
  57. x:
  58. Math.max(safeArea.left, SCROLLBAR_MARGIN) +
  59. ((viewportMinX - sceneMinX) / (sceneMaxX - sceneMinX)) *
  60. viewportWidth,
  61. y:
  62. viewportHeight -
  63. SCROLLBAR_WIDTH -
  64. Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
  65. width:
  66. ((viewportMaxX - viewportMinX) / (sceneMaxX - sceneMinX)) *
  67. viewportWidth -
  68. Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right),
  69. height: SCROLLBAR_WIDTH,
  70. },
  71. vertical:
  72. viewportMinY === sceneMinY && viewportMaxY === sceneMaxY
  73. ? null
  74. : {
  75. x:
  76. viewportWidth -
  77. SCROLLBAR_WIDTH -
  78. Math.max(safeArea.right, SCROLLBAR_MARGIN),
  79. y:
  80. ((viewportMinY - sceneMinY) / (sceneMaxY - sceneMinY)) *
  81. viewportHeight +
  82. Math.max(safeArea.top, SCROLLBAR_MARGIN),
  83. width: SCROLLBAR_WIDTH,
  84. height:
  85. ((viewportMaxY - viewportMinY) / (sceneMaxY - sceneMinY)) *
  86. viewportHeight -
  87. Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom),
  88. },
  89. };
  90. }
  91. export function isOverScrollBars(scrollBars: ScrollBars, x: number, y: number) {
  92. const [isOverHorizontalScrollBar, isOverVerticalScrollBar] = [
  93. scrollBars.horizontal,
  94. scrollBars.vertical,
  95. ].map((scrollBar) => {
  96. return (
  97. scrollBar &&
  98. scrollBar.x <= x &&
  99. x <= scrollBar.x + scrollBar.width &&
  100. scrollBar.y <= y &&
  101. y <= scrollBar.y + scrollBar.height
  102. );
  103. });
  104. return {
  105. isOverHorizontalScrollBar,
  106. isOverVerticalScrollBar,
  107. };
  108. }