Browse Source

fix: Visibility and zooming when canvas offset is not zero (#2534)

João Forja 4 years ago
parent
commit
4c7b1a2269

+ 15 - 5
src/actions/actionCanvas.tsx

@@ -95,6 +95,7 @@ export const actionZoomIn = register({
     const zoom = getNewZoom(
     const zoom = getNewZoom(
       getNormalizedZoom(appState.zoom.value + ZOOM_STEP),
       getNormalizedZoom(appState.zoom.value + ZOOM_STEP),
       appState.zoom,
       appState.zoom,
+      { left: appState.offsetLeft, top: appState.offsetTop },
       { x: appState.width / 2, y: appState.height / 2 },
       { x: appState.width / 2, y: appState.height / 2 },
     );
     );
     trackEvent(EVENT_ACTION, "zoom", "in", zoom.value * 100);
     trackEvent(EVENT_ACTION, "zoom", "in", zoom.value * 100);
@@ -128,6 +129,7 @@ export const actionZoomOut = register({
     const zoom = getNewZoom(
     const zoom = getNewZoom(
       getNormalizedZoom(appState.zoom.value - ZOOM_STEP),
       getNormalizedZoom(appState.zoom.value - ZOOM_STEP),
       appState.zoom,
       appState.zoom,
+      { left: appState.offsetLeft, top: appState.offsetTop },
       { x: appState.width / 2, y: appState.height / 2 },
       { x: appState.width / 2, y: appState.height / 2 },
     );
     );
 
 
@@ -163,10 +165,15 @@ export const actionResetZoom = register({
     return {
     return {
       appState: {
       appState: {
         ...appState,
         ...appState,
-        zoom: getNewZoom(1 as NormalizedZoomValue, appState.zoom, {
-          x: appState.width / 2,
-          y: appState.height / 2,
-        }),
+        zoom: getNewZoom(
+          1 as NormalizedZoomValue,
+          appState.zoom,
+          { left: appState.offsetLeft, top: appState.offsetTop },
+          {
+            x: appState.width / 2,
+            y: appState.height / 2,
+          },
+        ),
       },
       },
       commitToHistory: false,
       commitToHistory: false,
     };
     };
@@ -223,7 +230,10 @@ const zoomToFitElements = (
     width: appState.width,
     width: appState.width,
     height: appState.height,
     height: appState.height,
   });
   });
-  const newZoom = getNewZoom(zoomValue, appState.zoom);
+  const newZoom = getNewZoom(zoomValue, appState.zoom, {
+    left: appState.offsetLeft,
+    top: appState.offsetTop,
+  });
   const action = zoomToSelection ? "selection" : "fit";
   const action = zoomToSelection ? "selection" : "fit";
 
 
   const [x1, y1, x2, y2] = commonBounds;
   const [x1, y1, x2, y2] = commonBounds;

+ 17 - 10
src/components/App.tsx

@@ -1423,10 +1423,11 @@ class App extends React.Component<ExcalidrawProps, AppState> {
 
 
   private onGestureChange = withBatchedUpdates((event: GestureEvent) => {
   private onGestureChange = withBatchedUpdates((event: GestureEvent) => {
     event.preventDefault();
     event.preventDefault();
-    this.setState(({ zoom }) => ({
+    this.setState(({ zoom, offsetLeft, offsetTop }) => ({
       zoom: getNewZoom(
       zoom: getNewZoom(
         getNormalizedZoom(gesture.initialScale! * event.scale),
         getNormalizedZoom(gesture.initialScale! * event.scale),
         zoom,
         zoom,
+        { left: offsetLeft, top: offsetTop },
         { x: cursorX, y: cursorY },
         { x: cursorX, y: cursorY },
       ),
       ),
     }));
     }));
@@ -1750,12 +1751,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
       const distance = getDistance(Array.from(gesture.pointers.values()));
       const distance = getDistance(Array.from(gesture.pointers.values()));
       const scaleFactor = distance / gesture.initialDistance!;
       const scaleFactor = distance / gesture.initialDistance!;
 
 
-      this.setState(({ zoom, scrollX, scrollY }) => ({
+      this.setState(({ zoom, scrollX, scrollY, offsetLeft, offsetTop }) => ({
         scrollX: normalizeScroll(scrollX + deltaX / zoom.value),
         scrollX: normalizeScroll(scrollX + deltaX / zoom.value),
         scrollY: normalizeScroll(scrollY + deltaY / zoom.value),
         scrollY: normalizeScroll(scrollY + deltaY / zoom.value),
         zoom: getNewZoom(
         zoom: getNewZoom(
           getNormalizedZoom(gesture.initialScale! * scaleFactor),
           getNormalizedZoom(gesture.initialScale! * scaleFactor),
           zoom,
           zoom,
+          { left: offsetLeft, top: offsetTop },
           center,
           center,
         ),
         ),
         shouldCacheIgnoreZoom: true,
         shouldCacheIgnoreZoom: true,
@@ -2586,9 +2588,9 @@ class App extends React.Component<ExcalidrawProps, AppState> {
       );
       );
 
 
       /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.
       /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.
-			 If so, we want it to be null for start and "arrow" for end. If the linear item is not 
-			 an arrow, we want it to be null for both. Otherwise, we want it to use the 
-			 values from appState. */
+      If so, we want it to be null for start and "arrow" for end. If the linear item is not
+      an arrow, we want it to be null for both. Otherwise, we want it to use the
+      values from appState. */
 
 
       const { currentItemStartArrowhead, currentItemEndArrowhead } = this.state;
       const { currentItemStartArrowhead, currentItemEndArrowhead } = this.state;
       const [startArrowhead, endArrowhead] =
       const [startArrowhead, endArrowhead] =
@@ -3702,11 +3704,16 @@ class App extends React.Component<ExcalidrawProps, AppState> {
         }, 1000);
         }, 1000);
       }
       }
 
 
-      this.setState(({ zoom }) => ({
-        zoom: getNewZoom(getNormalizedZoom(zoom.value - delta / 100), zoom, {
-          x: cursorX,
-          y: cursorY,
-        }),
+      this.setState(({ zoom, offsetLeft, offsetTop }) => ({
+        zoom: getNewZoom(
+          getNormalizedZoom(zoom.value - delta / 100),
+          zoom,
+          { left: offsetLeft, top: offsetTop },
+          {
+            x: cursorX,
+            y: cursorY,
+          },
+        ),
         selectedElementIds: {},
         selectedElementIds: {},
         previousSelectedElementIds:
         previousSelectedElementIds:
           Object.keys(selectedElementIds).length !== 0
           Object.keys(selectedElementIds).length !== 0

+ 7 - 0
src/packages/excalidraw/CHANGELOG.MD

@@ -1,4 +1,5 @@
 # Changelog
 # Changelog
+
 <!--
 <!--
 Guidelines for changelog:
 Guidelines for changelog:
 The change should be grouped under one of the below section and must contain PR link.
 The change should be grouped under one of the below section and must contain PR link.
@@ -14,6 +15,7 @@ Please add the latest change on the top under the correct section.
 ## [Unreleased]
 ## [Unreleased]
 
 
 ### Features
 ### Features
+
 - Add zoom to selection [#2522](https://github.com/excalidraw/excalidraw/pull/2522)
 - Add zoom to selection [#2522](https://github.com/excalidraw/excalidraw/pull/2522)
 - Insert Library items in the middle of the screen [#2527](https://github.com/excalidraw/excalidraw/pull/2527)
 - Insert Library items in the middle of the screen [#2527](https://github.com/excalidraw/excalidraw/pull/2527)
 - Show shortcut context menu [#2501](https://github.com/excalidraw/excalidraw/pull/2501)
 - Show shortcut context menu [#2501](https://github.com/excalidraw/excalidraw/pull/2501)
@@ -23,9 +25,12 @@ Please add the latest change on the top under the correct section.
 - Support CSV graphs and improve the look and feel [#2495](https://github.com/excalidraw/excalidraw/pull/2495)
 - Support CSV graphs and improve the look and feel [#2495](https://github.com/excalidraw/excalidraw/pull/2495)
 
 
 ### Fixes
 ### Fixes
+
+- Fix element visibility and zoom on cursor when canvas offset isn't 0. [#2534](https://github.com/excalidraw/excalidraw/pull/2534)
 - Fix Library Menu Layout [#2502](https://github.com/excalidraw/excalidraw/pull/2502)
 - Fix Library Menu Layout [#2502](https://github.com/excalidraw/excalidraw/pull/2502)
 
 
 ### Improvements
 ### Improvements
+
 - Add tooltip with icon for embedding scenes [#2532](https://github.com/excalidraw/excalidraw/pull/2532)
 - Add tooltip with icon for embedding scenes [#2532](https://github.com/excalidraw/excalidraw/pull/2532)
 - RTL support for the stats dialog [#2530](https://github.com/excalidraw/excalidraw/pull/2530)
 - RTL support for the stats dialog [#2530](https://github.com/excalidraw/excalidraw/pull/2530)
 - Expand canvas padding based on zoom. [#2515](https://github.com/excalidraw/excalidraw/pull/2515)
 - Expand canvas padding based on zoom. [#2515](https://github.com/excalidraw/excalidraw/pull/2515)
@@ -33,11 +38,13 @@ Please add the latest change on the top under the correct section.
 - Hide stats and scrollToContent-button when mobile menus open [#2509](https://github.com/excalidraw/excalidraw/pull/2509)
 - Hide stats and scrollToContent-button when mobile menus open [#2509](https://github.com/excalidraw/excalidraw/pull/2509)
 
 
 ### Chore
 ### Chore
+
 - Bump ini from 1.3.5 to 1.3.7 in /src/packages/excalidraw [#2500](https://github.com/excalidraw/excalidraw/pull/2500)
 - Bump ini from 1.3.5 to 1.3.7 in /src/packages/excalidraw [#2500](https://github.com/excalidraw/excalidraw/pull/2500)
 
 
 ## 0.1.1
 ## 0.1.1
 
 
 #### Fix
 #### Fix
+
 - Update the homepage URL so it redirects to correct readme [#2498](https://github.com/excalidraw/excalidraw/pull/2498)
 - Update the homepage URL so it redirects to correct readme [#2498](https://github.com/excalidraw/excalidraw/pull/2498)
 
 
 ## 0.1.0
 ## 0.1.0

+ 9 - 2
src/renderer/renderScene.ts

@@ -763,13 +763,20 @@ const isVisibleElement = (
 ) => {
 ) => {
   const [x1, y1, x2, y2] = getElementBounds(element); // scene coordinates
   const [x1, y1, x2, y2] = getElementBounds(element); // scene coordinates
   const topLeftSceneCoords = viewportCoordsToSceneCoords(
   const topLeftSceneCoords = viewportCoordsToSceneCoords(
-    { clientX: 0, clientY: 0 },
+    {
+      clientX: viewTransformations.offsetLeft,
+      clientY: viewTransformations.offsetTop,
+    },
     viewTransformations,
     viewTransformations,
   );
   );
   const bottomRightSceneCoords = viewportCoordsToSceneCoords(
   const bottomRightSceneCoords = viewportCoordsToSceneCoords(
-    { clientX: canvasWidth, clientY: canvasHeight },
+    {
+      clientX: viewTransformations.offsetLeft + canvasWidth,
+      clientY: viewTransformations.offsetTop + canvasHeight,
+    },
     viewTransformations,
     viewTransformations,
   );
   );
+
   return (
   return (
     topLeftSceneCoords.x <= x2 &&
     topLeftSceneCoords.x <= x2 &&
     topLeftSceneCoords.y <= y2 &&
     topLeftSceneCoords.y <= y2 &&

+ 5 - 2
src/scene/zoom.ts

@@ -3,6 +3,7 @@ import { NormalizedZoomValue, PointerCoords, Zoom } from "../types";
 export const getNewZoom = (
 export const getNewZoom = (
   newZoomValue: NormalizedZoomValue,
   newZoomValue: NormalizedZoomValue,
   prevZoom: Zoom,
   prevZoom: Zoom,
+  canvasOffset: { left: number; top: number },
   zoomOnViewportPoint: PointerCoords = { x: 0, y: 0 },
   zoomOnViewportPoint: PointerCoords = { x: 0, y: 0 },
 ): Zoom => {
 ): Zoom => {
   return {
   return {
@@ -10,11 +11,13 @@ export const getNewZoom = (
     translation: {
     translation: {
       x:
       x:
         zoomOnViewportPoint.x -
         zoomOnViewportPoint.x -
-        (zoomOnViewportPoint.x - prevZoom.translation.x) *
+        canvasOffset.left -
+        (zoomOnViewportPoint.x - canvasOffset.left - prevZoom.translation.x) *
           (newZoomValue / prevZoom.value),
           (newZoomValue / prevZoom.value),
       y:
       y:
         zoomOnViewportPoint.y -
         zoomOnViewportPoint.y -
-        (zoomOnViewportPoint.y - prevZoom.translation.y) *
+        canvasOffset.top -
+        (zoomOnViewportPoint.y - canvasOffset.top - prevZoom.translation.y) *
           (newZoomValue / prevZoom.value),
           (newZoomValue / prevZoom.value),
     },
     },
   };
   };