fitToContent.test.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { render } from "./test-utils";
  2. import { API } from "./helpers/api";
  3. import { Excalidraw } from "../index";
  4. import { vi } from "vitest";
  5. const { h } = window;
  6. describe("fitToContent", () => {
  7. it("should zoom to fit the selected element", async () => {
  8. await render(<Excalidraw />);
  9. h.state.width = 10;
  10. h.state.height = 10;
  11. const rectElement = API.createElement({
  12. width: 50,
  13. height: 100,
  14. x: 50,
  15. y: 100,
  16. });
  17. expect(h.state.zoom.value).toBe(1);
  18. h.app.scrollToContent(rectElement, { fitToContent: true });
  19. // element is 10x taller than the viewport size,
  20. // zoom should be at least 1/10
  21. expect(h.state.zoom.value).toBeLessThanOrEqual(0.1);
  22. });
  23. it("should zoom to fit multiple elements", async () => {
  24. await render(<Excalidraw />);
  25. const topLeft = API.createElement({
  26. width: 20,
  27. height: 20,
  28. x: 0,
  29. y: 0,
  30. });
  31. const bottomRight = API.createElement({
  32. width: 20,
  33. height: 20,
  34. x: 80,
  35. y: 80,
  36. });
  37. h.state.width = 10;
  38. h.state.height = 10;
  39. expect(h.state.zoom.value).toBe(1);
  40. h.app.scrollToContent([topLeft, bottomRight], {
  41. fitToContent: true,
  42. });
  43. // elements take 100x100, which is 10x bigger than the viewport size,
  44. // zoom should be at least 1/10
  45. expect(h.state.zoom.value).toBeLessThanOrEqual(0.1);
  46. });
  47. it("should scroll the viewport to the selected element", async () => {
  48. await render(<Excalidraw />);
  49. h.state.width = 10;
  50. h.state.height = 10;
  51. const rectElement = API.createElement({
  52. width: 100,
  53. height: 100,
  54. x: 100,
  55. y: 100,
  56. });
  57. expect(h.state.zoom.value).toBe(1);
  58. expect(h.state.scrollX).toBe(0);
  59. expect(h.state.scrollY).toBe(0);
  60. h.app.scrollToContent(rectElement);
  61. // zoom level should stay the same
  62. expect(h.state.zoom.value).toBe(1);
  63. // state should reflect some scrolling
  64. expect(h.state.scrollX).not.toBe(0);
  65. expect(h.state.scrollY).not.toBe(0);
  66. });
  67. });
  68. const waitForNextAnimationFrame = () => {
  69. return new Promise((resolve) => {
  70. requestAnimationFrame(() => {
  71. requestAnimationFrame(resolve);
  72. });
  73. });
  74. };
  75. describe("fitToContent animated", () => {
  76. beforeEach(() => {
  77. vi.spyOn(window, "requestAnimationFrame");
  78. });
  79. afterEach(() => {
  80. vi.restoreAllMocks();
  81. });
  82. it("should ease scroll the viewport to the selected element", async () => {
  83. await render(<Excalidraw />);
  84. h.state.width = 10;
  85. h.state.height = 10;
  86. const rectElement = API.createElement({
  87. width: 100,
  88. height: 100,
  89. x: -100,
  90. y: -100,
  91. });
  92. h.app.scrollToContent(rectElement, { animate: true });
  93. expect(window.requestAnimationFrame).toHaveBeenCalled();
  94. // Since this is an animation, we expect values to change through time.
  95. // We'll verify that the scroll values change at 50ms and 100ms
  96. expect(h.state.scrollX).toBe(0);
  97. expect(h.state.scrollY).toBe(0);
  98. await waitForNextAnimationFrame();
  99. const prevScrollX = h.state.scrollX;
  100. const prevScrollY = h.state.scrollY;
  101. expect(h.state.scrollX).not.toBe(0);
  102. expect(h.state.scrollY).not.toBe(0);
  103. await waitForNextAnimationFrame();
  104. expect(h.state.scrollX).not.toBe(prevScrollX);
  105. expect(h.state.scrollY).not.toBe(prevScrollY);
  106. });
  107. it("should animate the scroll but not the zoom", async () => {
  108. await render(<Excalidraw />);
  109. h.state.width = 50;
  110. h.state.height = 50;
  111. const rectElement = API.createElement({
  112. width: 100,
  113. height: 100,
  114. x: 100,
  115. y: 100,
  116. });
  117. expect(h.state.scrollX).toBe(0);
  118. expect(h.state.scrollY).toBe(0);
  119. h.app.scrollToContent(rectElement, { animate: true, fitToContent: true });
  120. expect(window.requestAnimationFrame).toHaveBeenCalled();
  121. await waitForNextAnimationFrame();
  122. const prevScrollX = h.state.scrollX;
  123. const prevScrollY = h.state.scrollY;
  124. expect(h.state.scrollX).not.toBe(0);
  125. expect(h.state.scrollY).not.toBe(0);
  126. await waitForNextAnimationFrame();
  127. expect(h.state.scrollX).not.toBe(prevScrollX);
  128. expect(h.state.scrollY).not.toBe(prevScrollY);
  129. });
  130. });