Browse Source

[fix] Fixes off-center bugs (#101)

* moves center from window center to center of element

* Removes onMount in Renderer, adds onBoundsChange

* Fix centered-g css

* Fix zoom to fit
main
Steve Ruiz 4 years ago
parent
commit
68efbf69fa
No account linked to committer's email address

+ 2
- 2
packages/core/src/components/page/page.tsx View File

@@ -34,7 +34,7 @@ export function Page<T extends TLShape, M extends Record<string, unknown>>({
34 34
     page,
35 35
     pageState,
36 36
     shapeUtils,
37
-    inputs.size,
37
+    [inputs.bounds.width, inputs.bounds.height],
38 38
     meta,
39 39
     callbacks.onRenderCountChange
40 40
   )
@@ -59,7 +59,7 @@ export function Page<T extends TLShape, M extends Record<string, unknown>>({
59 59
         <Bounds
60 60
           zoom={zoom}
61 61
           bounds={bounds}
62
-          viewportWidth={inputs.size[0]}
62
+          viewportWidth={inputs.bounds.width}
63 63
           isLocked={isLocked}
64 64
           rotation={rotation}
65 65
         />

+ 7
- 3
packages/core/src/components/renderer/renderer.tsx View File

@@ -56,9 +56,13 @@ export interface RendererProps<T extends TLShape, E extends Element = any, M = a
56 56
    */
57 57
   meta?: M
58 58
   /**
59
-   * A callback that receives the renderer's inputs manager.
59
+   * (optional) A callback that receives the renderer's inputs manager.
60 60
    */
61 61
   onMount?: (inputs: Inputs) => void
62
+  /**
63
+   * (optional) A callback that is fired when the editor's client bounding box changes.
64
+   */
65
+  onBoundsChange?: (bounds: TLBounds) => void
62 66
 }
63 67
 
64 68
 /**
@@ -83,7 +87,7 @@ export function Renderer<T extends TLShape, E extends Element, M extends Record<
83 87
 }: RendererProps<T, E, M>): JSX.Element {
84 88
   useTLTheme(theme)
85 89
 
86
-  const rScreenBounds = React.useRef<TLBounds>(null)
90
+  const rSelectionBounds = React.useRef<TLBounds>(null)
87 91
 
88 92
   const rPageState = React.useRef<TLPageState>(pageState)
89 93
 
@@ -96,7 +100,7 @@ export function Renderer<T extends TLShape, E extends Element, M extends Record<
96 100
   const [context] = React.useState<TLContextType<T, E, M>>(() => ({
97 101
     callbacks: rest,
98 102
     shapeUtils,
99
-    rScreenBounds,
103
+    rSelectionBounds,
100 104
     rPageState,
101 105
     inputs: new Inputs(),
102 106
   }))

+ 0
- 12
packages/core/src/hooks/useCameraCss.tsx View File

@@ -15,17 +15,5 @@ export function useCameraCss(ref: React.RefObject<HTMLDivElement>, pageState: TL
15 15
     ref.current!.style.setProperty('--tl-camera-y', pageState.camera.point[1] + 'px')
16 16
   }, [pageState.camera.point])
17 17
 
18
-  // Update the group's position when the camera moves or zooms
19
-  // React.useEffect(() => {
20
-  //   const {
21
-  //     zoom,
22
-  //     point: [x = 0, y = 0],
23
-  //   } = pageState.camera
24
-  //   rLayer.current?.style.setProperty(
25
-  //     'transform',
26
-  //     `scale(${zoom},${zoom}) translate(${x}px,${y}px)`
27
-  //   )
28
-  // }, [pageState.camera])
29
-
30 18
   return rLayer
31 19
 }

+ 8
- 1
packages/core/src/hooks/usePosition.ts View File

@@ -5,11 +5,18 @@ import type { TLBounds } from '+types'
5 5
 export function usePosition(bounds: TLBounds, rotation = 0) {
6 6
   const rBounds = React.useRef<HTMLDivElement>(null)
7 7
 
8
+  // Update the transform
8 9
   React.useLayoutEffect(() => {
9 10
     const elm = rBounds.current!
11
+
10 12
     const transform = `
11
-    translate(calc(${bounds.minX}px - var(--tl-padding)),calc(${bounds.minY}px - var(--tl-padding)))
13
+    translate3d(
14
+      calc(${bounds.minX}px - var(--tl-padding)),
15
+      calc(${bounds.minY}px - var(--tl-padding)), 
16
+      0px
17
+    )
12 18
     rotate(${rotation + (bounds.rotation || 0)}rad)`
19
+
13 20
     elm.style.setProperty('transform', transform)
14 21
 
15 22
     elm.style.setProperty('width', `calc(${Math.floor(bounds.width)}px + (var(--tl-padding) * 2))`)

+ 31
- 14
packages/core/src/hooks/useResizeObserver.ts View File

@@ -3,31 +3,48 @@ import * as React from 'react'
3 3
 import { Utils } from '+utils'
4 4
 
5 5
 export function useResizeObserver<T extends Element>(ref: React.RefObject<T>) {
6
-  const { inputs } = useTLContext()
6
+  const { inputs, callbacks } = useTLContext()
7
+
7 8
   const rIsMounted = React.useRef(false)
9
+
8 10
   const forceUpdate = React.useReducer((x) => x + 1, 0)[1]
9 11
 
10
-  const updateOffsets = React.useCallback(() => {
12
+  // When the element resizes, update the bounds (stored in inputs)
13
+  // and broadcast via the onBoundsChange callback prop.
14
+  const updateBounds = React.useCallback(() => {
11 15
     if (rIsMounted.current) {
12 16
       const rect = ref.current?.getBoundingClientRect()
17
+
13 18
       if (rect) {
14
-        inputs.offset = [rect.left, rect.top]
15
-        inputs.size = [rect.width, rect.height]
19
+        inputs.bounds = {
20
+          minX: rect.left,
21
+          maxX: rect.left + rect.width,
22
+          minY: rect.top,
23
+          maxY: rect.top + rect.height,
24
+          width: rect.width,
25
+          height: rect.height,
26
+        }
27
+
28
+        callbacks.onBoundsChange?.(inputs.bounds)
29
+
30
+        // Force an update for a second mount
16 31
         forceUpdate()
17 32
       }
33
+    } else {
34
+      // Skip the first mount
35
+      rIsMounted.current = true
18 36
     }
19
-    rIsMounted.current = true
20
-  }, [ref, forceUpdate])
37
+  }, [ref, forceUpdate, inputs, callbacks.onBoundsChange])
21 38
 
22 39
   React.useEffect(() => {
23
-    const debouncedUpdateOffsets = Utils.debounce(updateOffsets, 100)
24
-    window.addEventListener('scroll', debouncedUpdateOffsets)
25
-    window.addEventListener('resize', debouncedUpdateOffsets)
40
+    const debouncedupdateBounds = Utils.debounce(updateBounds, 100)
41
+    window.addEventListener('scroll', debouncedupdateBounds)
42
+    window.addEventListener('resize', debouncedupdateBounds)
26 43
     return () => {
27
-      window.removeEventListener('scroll', debouncedUpdateOffsets)
28
-      window.removeEventListener('resize', debouncedUpdateOffsets)
44
+      window.removeEventListener('scroll', debouncedupdateBounds)
45
+      window.removeEventListener('resize', debouncedupdateBounds)
29 46
     }
30
-  }, [inputs])
47
+  }, [])
31 48
 
32 49
   React.useEffect(() => {
33 50
     const resizeObserver = new ResizeObserver((entries) => {
@@ -36,7 +53,7 @@ export function useResizeObserver<T extends Element>(ref: React.RefObject<T>) {
36 53
       }
37 54
 
38 55
       if (entries[0].contentRect) {
39
-        updateOffsets()
56
+        updateBounds()
40 57
       }
41 58
     })
42 59
 
@@ -50,6 +67,6 @@ export function useResizeObserver<T extends Element>(ref: React.RefObject<T>) {
50 67
   }, [ref, inputs])
51 68
 
52 69
   React.useEffect(() => {
53
-    updateOffsets()
70
+    updateBounds()
54 71
   }, [ref])
55 72
 }

+ 3
- 3
packages/core/src/hooks/useSelection.tsx View File

@@ -11,7 +11,7 @@ export function useSelection<T extends TLShape, E extends Element>(
11 11
   pageState: TLPageState,
12 12
   shapeUtils: TLShapeUtils<T, E>
13 13
 ) {
14
-  const { rScreenBounds } = useTLContext()
14
+  const { rSelectionBounds } = useTLContext()
15 15
   const { selectedIds } = pageState
16 16
 
17 17
   let bounds: TLBounds | undefined = undefined
@@ -50,7 +50,7 @@ export function useSelection<T extends TLShape, E extends Element>(
50 50
     const [minX, minY] = canvasToScreen([bounds.minX, bounds.minY], pageState.camera)
51 51
     const [maxX, maxY] = canvasToScreen([bounds.maxX, bounds.maxY], pageState.camera)
52 52
 
53
-    rScreenBounds.current = {
53
+    rSelectionBounds.current = {
54 54
       minX,
55 55
       minY,
56 56
       maxX,
@@ -59,7 +59,7 @@ export function useSelection<T extends TLShape, E extends Element>(
59 59
       height: maxY - minY,
60 60
     }
61 61
   } else {
62
-    rScreenBounds.current = null
62
+    rSelectionBounds.current = null
63 63
   }
64 64
 
65 65
   return { bounds, rotation, isLocked }

+ 3
- 3
packages/core/src/hooks/useShapeEvents.tsx View File

@@ -3,7 +3,7 @@ import { Utils } from '+utils'
3 3
 import { TLContext } from '+hooks'
4 4
 
5 5
 export function useShapeEvents(id: string, disable = false) {
6
-  const { rPageState, rScreenBounds, callbacks, inputs } = React.useContext(TLContext)
6
+  const { rPageState, rSelectionBounds, callbacks, inputs } = React.useContext(TLContext)
7 7
 
8 8
   const onPointerDown = React.useCallback(
9 9
     (e: React.PointerEvent) => {
@@ -26,8 +26,8 @@ export function useShapeEvents(id: string, disable = false) {
26 26
       // treat the event as a bounding box click. Unfortunately there's no way I know to pipe
27 27
       // the event to the actual bounds background element.
28 28
       if (
29
-        rScreenBounds.current &&
30
-        Utils.pointInBounds(info.point, rScreenBounds.current) &&
29
+        rSelectionBounds.current &&
30
+        Utils.pointInBounds(info.point, rSelectionBounds.current) &&
31 31
         !rPageState.current.selectedIds.includes(id)
32 32
       ) {
33 33
         callbacks.onPointBounds?.(inputs.pointerDown(e, 'bounds'), e)

+ 1
- 2
packages/core/src/hooks/useStyle.tsx View File

@@ -151,8 +151,7 @@ const tlcss = css`
151 151
     height: 0;
152 152
     width: 0;
153 153
     contain: layout size;
154
-    transform: scale(var(--tl-zoom), var(--tl-zoom))
155
-      translate(var(--tl-camera-x), var(--tl-camera-y));
154
+    transform: scale(var(--tl-zoom)) translate3d(var(--tl-camera-x), var(--tl-camera-y), 0px);
156 155
   }
157 156
 
158 157
   .tl-absolute {

+ 2
- 1
packages/core/src/hooks/useTLContext.tsx View File

@@ -2,12 +2,13 @@ import * as React from 'react'
2 2
 import type { Inputs } from '+inputs'
3 3
 import type { TLCallbacks, TLShape, TLBounds, TLPageState, TLShapeUtils } from '+types'
4 4
 
5
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
5 6
 export interface TLContextType<T extends TLShape, E extends Element, M = any> {
6 7
   id?: string
7 8
   callbacks: Partial<TLCallbacks<T>>
8 9
   shapeUtils: TLShapeUtils<T, E, M>
9 10
   rPageState: React.MutableRefObject<TLPageState>
10
-  rScreenBounds: React.MutableRefObject<TLBounds | null>
11
+  rSelectionBounds: React.MutableRefObject<TLBounds | null>
11 12
   inputs: Inputs
12 13
 }
13 14
 

+ 26
- 16
packages/core/src/inputs.ts View File

@@ -2,17 +2,27 @@ import type React from 'react'
2 2
 import type { TLKeyboardInfo, TLPointerInfo } from './types'
3 3
 import { Utils } from './utils'
4 4
 import { Vec } from '@tldraw/vec'
5
+import type { TLBounds } from '+index'
5 6
 
6 7
 const DOUBLE_CLICK_DURATION = 250
7 8
 
8 9
 export class Inputs {
9 10
   pointer?: TLPointerInfo<string>
11
+
10 12
   keyboard?: TLKeyboardInfo
13
+
11 14
   keys: Record<string, boolean> = {}
15
+
12 16
   isPinching = false
13 17
 
14
-  offset = [0, 0]
15
-  size = [10, 10]
18
+  bounds: TLBounds = {
19
+    minX: 0,
20
+    maxX: 640,
21
+    minY: 0,
22
+    maxY: 480,
23
+    width: 640,
24
+    height: 480,
25
+  }
16 26
 
17 27
   pointerUpTime = 0
18 28
 
@@ -41,9 +51,9 @@ export class Inputs {
41 51
     const info: TLPointerInfo<T> = {
42 52
       target,
43 53
       pointerId: touch.identifier,
44
-      origin: Inputs.getPoint(touch),
54
+      origin: Inputs.getPoint(touch, this.bounds),
45 55
       delta: [0, 0],
46
-      point: Inputs.getPoint(touch),
56
+      point: Inputs.getPoint(touch, this.bounds),
47 57
       pressure: Inputs.getPressure(touch),
48 58
       shiftKey,
49 59
       ctrlKey,
@@ -64,9 +74,9 @@ export class Inputs {
64 74
     const info: TLPointerInfo<T> = {
65 75
       target,
66 76
       pointerId: touch.identifier,
67
-      origin: Inputs.getPoint(touch),
77
+      origin: Inputs.getPoint(touch, this.bounds),
68 78
       delta: [0, 0],
69
-      point: Inputs.getPoint(touch),
79
+      point: Inputs.getPoint(touch, this.bounds),
70 80
       pressure: Inputs.getPressure(touch),
71 81
       shiftKey,
72 82
       ctrlKey,
@@ -88,7 +98,7 @@ export class Inputs {
88 98
 
89 99
     const prev = this.pointer
90 100
 
91
-    const point = Inputs.getPoint(touch)
101
+    const point = Inputs.getPoint(touch, this.bounds)
92 102
 
93 103
     const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
94 104
 
@@ -114,7 +124,7 @@ export class Inputs {
114 124
   pointerDown<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
115 125
     const { shiftKey, ctrlKey, metaKey, altKey } = e
116 126
 
117
-    const point = Inputs.getPoint(e, this.offset)
127
+    const point = Inputs.getPoint(e, this.bounds)
118 128
 
119 129
     this.activePointer = e.pointerId
120 130
 
@@ -142,7 +152,7 @@ export class Inputs {
142 152
   ): TLPointerInfo<T> {
143 153
     const { shiftKey, ctrlKey, metaKey, altKey } = e
144 154
 
145
-    const point = Inputs.getPoint(e, this.offset)
155
+    const point = Inputs.getPoint(e, this.bounds)
146 156
 
147 157
     const info: TLPointerInfo<T> = {
148 158
       target,
@@ -167,7 +177,7 @@ export class Inputs {
167 177
 
168 178
     const prev = this.pointer
169 179
 
170
-    const point = Inputs.getPoint(e, this.offset)
180
+    const point = Inputs.getPoint(e, this.bounds)
171 181
 
172 182
     const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
173 183
 
@@ -195,7 +205,7 @@ export class Inputs {
195 205
 
196 206
     const prev = this.pointer
197 207
 
198
-    const point = Inputs.getPoint(e, this.offset)
208
+    const point = Inputs.getPoint(e, this.bounds)
199 209
 
200 210
     const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
201 211
 
@@ -231,7 +241,7 @@ export class Inputs {
231 241
       origin: this.pointer?.origin || [0, 0],
232 242
       delta: [0, 0],
233 243
       pressure: 0.5,
234
-      point: Inputs.getPoint(e, this.offset),
244
+      point: Inputs.getPoint(e, this.bounds),
235 245
       shiftKey,
236 246
       ctrlKey,
237 247
       metaKey,
@@ -252,7 +262,7 @@ export class Inputs {
252 262
 
253 263
     const prev = this.pointer
254 264
 
255
-    const point = Inputs.getPoint(e, this.offset)
265
+    const point = Inputs.getPoint(e, this.bounds)
256 266
 
257 267
     const info: TLPointerInfo<'wheel'> = {
258 268
       ...prev,
@@ -330,7 +340,7 @@ export class Inputs {
330 340
       target: 'pinch',
331 341
       origin,
332 342
       delta: delta,
333
-      point: Vec.sub(Vec.round(point), this.offset),
343
+      point: Vec.sub(Vec.round(point), [this.bounds.minX, this.bounds.minY]),
334 344
       pressure: 0.5,
335 345
       shiftKey,
336 346
       ctrlKey,
@@ -353,9 +363,9 @@ export class Inputs {
353 363
 
354 364
   static getPoint(
355 365
     e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent,
356
-    offset = [0, 0]
366
+    bounds: TLBounds
357 367
   ): number[] {
358
-    return [+e.clientX.toFixed(2) - offset[0], +e.clientY.toFixed(2) - offset[1]]
368
+    return [+e.clientX.toFixed(2) - bounds.minX, +e.clientY.toFixed(2) - bounds.minY]
359 369
   }
360 370
 
361 371
   static getPressure(e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent) {

+ 2
- 2
packages/core/src/test/context-wrapper.tsx View File

@@ -7,13 +7,13 @@ import { Inputs } from '+inputs'
7 7
 
8 8
 export const ContextWrapper: React.FC = ({ children }) => {
9 9
   useTLTheme()
10
-  const rScreenBounds = React.useRef<TLBounds>(null)
10
+  const rSelectionBounds = React.useRef<TLBounds>(null)
11 11
   const rPageState = React.useRef<TLPageState>(mockDocument.pageState)
12 12
 
13 13
   const [context] = React.useState(() => ({
14 14
     callbacks: {},
15 15
     shapeUtils: mockUtils,
16
-    rScreenBounds,
16
+    rSelectionBounds,
17 17
     rPageState,
18 18
     inputs: new Inputs(),
19 19
   }))

+ 1
- 0
packages/core/src/types.ts View File

@@ -205,6 +205,7 @@ export interface TLCallbacks<T extends TLShape> {
205 205
   onShapeBlur: TLShapeBlurHandler<any>
206 206
   onRenderCountChange: (ids: string[]) => void
207 207
   onError: (error: Error) => void
208
+  onBoundsChange: (bounds: TLBounds) => void
208 209
 }
209 210
 
210 211
 export interface TLBounds {

+ 1
- 1
packages/tldraw/src/components/tldraw/tldraw.tsx View File

@@ -220,7 +220,7 @@ function InnerTldraw({
220 220
           onRenderCountChange={tlstate.onRenderCountChange}
221 221
           onShapeChange={tlstate.onShapeChange}
222 222
           onShapeBlur={tlstate.onShapeBlur}
223
-          onMount={tlstate.handleMount}
223
+          onBoundsChange={tlstate.updateBounds}
224 224
         />
225 225
       </ContextMenu>
226 226
       <div className={menuButtons()}>

+ 0
- 14
packages/tldraw/src/state/tldr.ts View File

@@ -33,20 +33,6 @@ export class TLDR {
33 33
     return Vec.sub(Vec.div(point, camera.zoom), camera.point)
34 34
   }
35 35
 
36
-  static getViewport(data: Data): TLBounds {
37
-    const [minX, minY] = TLDR.screenToWorld(data, [0, 0])
38
-    const [maxX, maxY] = TLDR.screenToWorld(data, [window.innerWidth, window.innerHeight])
39
-
40
-    return {
41
-      minX,
42
-      minY,
43
-      maxX,
44
-      maxY,
45
-      height: maxX - minX,
46
-      width: maxY - minY,
47
-    }
48
-  }
49
-
50 36
   static getCameraZoom(zoom: number) {
51 37
     return Utils.clamp(zoom, 0.1, 5)
52 38
   }

+ 38
- 30
packages/tldraw/src/state/tlstate.ts View File

@@ -119,6 +119,16 @@ export class TLDrawState extends StateManager<Data> {
119 119
 
120 120
   selectedGroupId?: string
121 121
 
122
+  // The editor's bounding client rect
123
+  bounds: TLBounds = {
124
+    minX: 0,
125
+    minY: 0,
126
+    maxX: 640,
127
+    maxY: 480,
128
+    width: 640,
129
+    height: 480,
130
+  }
131
+
122 132
   private pasteInfo = {
123 133
     center: [0, 0],
124 134
     offset: [0, 0],
@@ -354,6 +364,14 @@ export class TLDrawState extends StateManager<Data> {
354 364
     this.inputs = inputs
355 365
   }
356 366
 
367
+  /**
368
+   * Update the bounding box when the renderer's bounds change.
369
+   * @param bounds
370
+   */
371
+  updateBounds = (bounds: TLBounds) => {
372
+    this.bounds = { ...bounds }
373
+  }
374
+
357 375
   /* -------------------------------------------------- */
358 376
   /*                    Settings & UI                   */
359 377
   /* -------------------------------------------------- */
@@ -861,14 +879,7 @@ export class TLDrawState extends StateManager<Data> {
861 879
 
862 880
       const commonBounds = Utils.getCommonBounds(shapesToPaste.map(TLDR.getBounds))
863 881
 
864
-      let center = Vec.round(
865
-        this.getPagePoint(
866
-          point ||
867
-            (this.inputs
868
-              ? [this.inputs.size[0] / 2, this.inputs.size[1] / 2]
869
-              : [window.innerWidth / 2, window.innerHeight / 2])
870
-        )
871
-      )
882
+      let center = Vec.round(this.getPagePoint(point || this.centerPoint))
872 883
 
873 884
       if (
874 885
         Vec.dist(center, this.pasteInfo.center) < 2 ||
@@ -914,10 +925,7 @@ export class TLDrawState extends StateManager<Data> {
914 925
             type: TLDrawShapeType.Text,
915 926
             parentId: this.appState.currentPageId,
916 927
             text: result,
917
-            point: this.getPagePoint(
918
-              [window.innerWidth / 2, window.innerHeight / 2],
919
-              this.currentPageId
920
-            ),
928
+            point: this.getPagePoint(this.centerPoint, this.currentPageId),
921 929
             style: { ...this.appState.currentStyle },
922 930
           })
923 931
 
@@ -1030,11 +1038,7 @@ export class TLDrawState extends StateManager<Data> {
1030 1038
    * Reset the camera to the default position
1031 1039
    */
1032 1040
   resetCamera = (): this => {
1033
-    return this.setCamera(
1034
-      Vec.round([window.innerWidth / 2, window.innerHeight / 2]),
1035
-      1,
1036
-      `reset_camera`
1037
-    )
1041
+    return this.setCamera(this.centerPoint, 1, `reset_camera`)
1038 1042
   }
1039 1043
 
1040 1044
   /**
@@ -1066,7 +1070,7 @@ export class TLDrawState extends StateManager<Data> {
1066 1070
    * @param next The new zoom level.
1067 1071
    * @param center The point to zoom towards (defaults to screen center).
1068 1072
    */
1069
-  zoomTo = (next: number, center = [window.innerWidth / 2, window.innerHeight / 2]): this => {
1073
+  zoomTo = (next: number, center = this.centerPoint): this => {
1070 1074
     const { zoom, point } = this.pageState.camera
1071 1075
     const p0 = Vec.sub(Vec.div(center, zoom), point)
1072 1076
     const p1 = Vec.sub(Vec.div(center, next), point)
@@ -1102,13 +1106,13 @@ export class TLDrawState extends StateManager<Data> {
1102 1106
     const bounds = Utils.getCommonBounds(Object.values(shapes).map(TLDR.getBounds))
1103 1107
 
1104 1108
     const zoom = TLDR.getCameraZoom(
1105
-      window.innerWidth < window.innerHeight
1106
-        ? (window.innerWidth - 128) / bounds.width
1107
-        : (window.innerHeight - 128) / bounds.height
1109
+      this.bounds.width < this.bounds.height
1110
+        ? (this.bounds.width - 128) / bounds.width
1111
+        : (this.bounds.height - 128) / bounds.height
1108 1112
     )
1109 1113
 
1110
-    const mx = (window.innerWidth - bounds.width * zoom) / 2 / zoom
1111
-    const my = (window.innerHeight - bounds.height * zoom) / 2 / zoom
1114
+    const mx = (this.bounds.width - bounds.width * zoom) / 2 / zoom
1115
+    const my = (this.bounds.height - bounds.height * zoom) / 2 / zoom
1112 1116
 
1113 1117
     return this.setCamera(
1114 1118
       Vec.round(Vec.add([-bounds.minX, -bounds.minY], [mx, my])),
@@ -1126,13 +1130,13 @@ export class TLDrawState extends StateManager<Data> {
1126 1130
     const bounds = TLDR.getSelectedBounds(this.state)
1127 1131
 
1128 1132
     const zoom = TLDR.getCameraZoom(
1129
-      window.innerWidth < window.innerHeight
1130
-        ? (window.innerWidth - 128) / bounds.width
1131
-        : (window.innerHeight - 128) / bounds.height
1133
+      this.bounds.width < this.bounds.height
1134
+        ? (this.bounds.width - 128) / bounds.width
1135
+        : (this.bounds.height - 128) / bounds.height
1132 1136
     )
1133 1137
 
1134
-    const mx = (window.innerWidth - bounds.width * zoom) / 2 / zoom
1135
-    const my = (window.innerHeight - bounds.height * zoom) / 2 / zoom
1138
+    const mx = (this.bounds.width - bounds.width * zoom) / 2 / zoom
1139
+    const my = (this.bounds.height - bounds.height * zoom) / 2 / zoom
1136 1140
 
1137 1141
     return this.setCamera(
1138 1142
       Vec.round(Vec.add([-bounds.minX, -bounds.minY], [mx, my])),
@@ -1153,8 +1157,8 @@ export class TLDrawState extends StateManager<Data> {
1153 1157
     const bounds = Utils.getCommonBounds(Object.values(shapes).map(TLDR.getBounds))
1154 1158
 
1155 1159
     const { zoom } = pageState.camera
1156
-    const mx = (window.innerWidth - bounds.width * zoom) / 2 / zoom
1157
-    const my = (window.innerHeight - bounds.height * zoom) / 2 / zoom
1160
+    const mx = (this.bounds.width - bounds.width * zoom) / 2 / zoom
1161
+    const my = (this.bounds.height - bounds.height * zoom) / 2 / zoom
1158 1162
 
1159 1163
     return this.setCamera(
1160 1164
       Vec.round(Vec.add([-bounds.minX, -bounds.minY], [mx, my])),
@@ -2813,4 +2817,8 @@ export class TLDrawState extends StateManager<Data> {
2813 2817
   onError = () => {
2814 2818
     // TODO
2815 2819
   }
2820
+
2821
+  get centerPoint() {
2822
+    return Vec.round(Utils.getBoundsCenter(this.bounds))
2823
+  }
2816 2824
 }

Loading…
Cancel
Save