scroll.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { AppState, FlooredNumber } from "../types";
  2. import { ExcalidrawElement } from "../element/types";
  3. import { getCommonBounds, getClosestElementBounds } from "../element";
  4. import {
  5. sceneCoordsToViewportCoords,
  6. viewportCoordsToSceneCoords,
  7. } from "../utils";
  8. export const normalizeScroll = (pos: number) =>
  9. Math.floor(pos) as FlooredNumber;
  10. function isOutsideViewPort(
  11. appState: AppState,
  12. canvas: HTMLCanvasElement | null,
  13. cords: Array<number>,
  14. ) {
  15. const [x1, y1, x2, y2] = cords;
  16. const { x: viewportX1, y: viewportY1 } = sceneCoordsToViewportCoords(
  17. { sceneX: x1, sceneY: y1 },
  18. appState,
  19. canvas,
  20. window.devicePixelRatio,
  21. );
  22. const { x: viewportX2, y: viewportY2 } = sceneCoordsToViewportCoords(
  23. { sceneX: x2, sceneY: y2 },
  24. appState,
  25. canvas,
  26. window.devicePixelRatio,
  27. );
  28. return (
  29. viewportX2 - viewportX1 > appState.width ||
  30. viewportY2 - viewportY1 > appState.height
  31. );
  32. }
  33. export const calculateScrollCenter = (
  34. elements: readonly ExcalidrawElement[],
  35. appState: AppState,
  36. canvas: HTMLCanvasElement | null,
  37. ): { scrollX: FlooredNumber; scrollY: FlooredNumber } => {
  38. if (!elements.length) {
  39. return {
  40. scrollX: normalizeScroll(0),
  41. scrollY: normalizeScroll(0),
  42. };
  43. }
  44. const scale = window.devicePixelRatio;
  45. let [x1, y1, x2, y2] = getCommonBounds(elements);
  46. if (isOutsideViewPort(appState, canvas, [x1, y1, x2, y2])) {
  47. [x1, y1, x2, y2] = getClosestElementBounds(
  48. elements,
  49. viewportCoordsToSceneCoords(
  50. { clientX: appState.scrollX, clientY: appState.scrollY },
  51. appState,
  52. canvas,
  53. scale,
  54. ),
  55. );
  56. }
  57. const centerX = (x1 + x2) / 2;
  58. const centerY = (y1 + y2) / 2;
  59. return {
  60. scrollX: normalizeScroll(appState.width / 2 - centerX),
  61. scrollY: normalizeScroll(appState.height / 2 - centerY),
  62. };
  63. };