Explorar el Código

Improves performance for certain actions

main
Steve Ruiz hace 4 años
padre
commit
704e92faa4

+ 9
- 35
components/canvas/canvas.tsx Ver fichero

11
 import BoundsBg from './bounds/bounds-bg'
11
 import BoundsBg from './bounds/bounds-bg'
12
 import Selected from './selected'
12
 import Selected from './selected'
13
 import Handles from './bounds/handles'
13
 import Handles from './bounds/handles'
14
-import { isMobile, throttle } from 'utils/utils'
14
+import { isMobile, screenToWorld, throttle } from 'utils/utils'
15
+import session from 'state/session'
16
+import { PointerInfo } from 'types'
17
+import { fastDrawUpdate } from 'state/hacks'
18
+import useCanvasEvents from 'hooks/useCanvasEvents'
15
 
19
 
16
 export default function Canvas() {
20
 export default function Canvas() {
17
   const rCanvas = useRef<SVGSVGElement>(null)
21
   const rCanvas = useRef<SVGSVGElement>(null)
18
   const rGroup = useRef<SVGGElement>(null)
22
   const rGroup = useRef<SVGGElement>(null)
19
 
23
 
20
   useCamera(rGroup)
24
   useCamera(rGroup)
21
-  useZoomEvents()
22
-
23
-  const isReady = useSelector((s) => s.isIn('ready'))
24
 
25
 
25
-  const handlePointerDown = useCallback((e: React.PointerEvent) => {
26
-    if (!inputs.canAccept(e.pointerId)) return
27
-    rCanvas.current.setPointerCapture(e.pointerId)
28
-    state.send('POINTED_CANVAS', inputs.pointerDown(e, 'canvas'))
29
-  }, [])
30
-
31
-  const handleTouchStart = useCallback((e: React.TouchEvent) => {
32
-    if (e.touches.length === 2) {
33
-      state.send('TOUCH_UNDO')
34
-    } else {
35
-      if (isMobile()) {
36
-        state.send('TOUCHED_CANVAS')
37
-      }
38
-    }
39
-  }, [])
26
+  useZoomEvents()
40
 
27
 
41
-  const handlePointerMove = useCallback((e: React.PointerEvent) => {
42
-    if (!inputs.canAccept(e.pointerId)) return
43
-    throttledPointerMove(inputs.pointerMove(e))
44
-  }, [])
28
+  const events = useCanvasEvents(rCanvas)
45
 
29
 
46
-  const handlePointerUp = useCallback((e: React.PointerEvent) => {
47
-    if (!inputs.canAccept(e.pointerId)) return
48
-    rCanvas.current.releasePointerCapture(e.pointerId)
49
-    state.send('STOPPED_POINTING', { id: 'canvas', ...inputs.pointerUp(e) })
50
-  }, [])
30
+  const isReady = useSelector((s) => s.isIn('ready'))
51
 
31
 
52
   return (
32
   return (
53
-    <MainSVG
54
-      ref={rCanvas}
55
-      onPointerDown={handlePointerDown}
56
-      onPointerMove={handlePointerMove}
57
-      onPointerUp={handlePointerUp}
58
-      onTouchStart={handleTouchStart}
59
-    >
33
+    <MainSVG ref={rCanvas} {...events}>
60
       <Defs />
34
       <Defs />
61
       {isReady && (
35
       {isReady && (
62
         <g ref={rGroup}>
36
         <g ref={rGroup}>

+ 40
- 8
components/canvas/page.tsx Ver fichero

1
-import { useSelector } from 'state'
2
-import { GroupShape } from 'types'
3
-import { deepCompareArrays, getPage } from 'utils/utils'
1
+import { getShapeUtils } from 'lib/shape-utils'
2
+import state, { useSelector } from 'state'
3
+import { Bounds, GroupShape, PageState } from 'types'
4
+import { boundsContain } from 'utils/bounds'
5
+import { deepCompareArrays, getPage, screenToWorld } from 'utils/utils'
4
 import Shape from './shape'
6
 import Shape from './shape'
5
 
7
 
6
 /* 
8
 /* 
11
 
13
 
12
 const noOffset = [0, 0]
14
 const noOffset = [0, 0]
13
 
15
 
16
+const viewportCache = new WeakMap<PageState, Bounds>()
17
+
14
 export default function Page() {
18
 export default function Page() {
15
-  const currentPageShapeIds = useSelector(({ data }) => {
16
-    return Object.values(getPage(data).shapes)
17
-      .filter((shape) => shape.parentId === data.currentPageId)
18
-      .sort((a, b) => a.childIndex - b.childIndex)
19
-      .map((shape) => shape.id)
19
+  const currentPageShapeIds = useSelector((s) => {
20
+    const page = getPage(s.data)
21
+    const pageState = s.data.pageStates[page.id]
22
+
23
+    // if (!viewportCache.has(pageState)) {
24
+    //   const [minX, minY] = screenToWorld([0, 0], s.data)
25
+    //   const [maxX, maxY] = screenToWorld(
26
+    //     [window.innerWidth, window.innerHeight],
27
+    //     s.data
28
+    //   )
29
+    //   viewportCache.set(pageState, {
30
+    //     minX,
31
+    //     minY,
32
+    //     maxX,
33
+    //     maxY,
34
+    //     height: maxX - minX,
35
+    //     width: maxY - minY,
36
+    //   })
37
+    // }
38
+
39
+    // const viewport = viewportCache.get(pageState)
40
+
41
+    return (
42
+      Object.values(page.shapes)
43
+        .filter((shape) => shape.parentId === page.id)
44
+        // .filter((shape) => {
45
+        //   const shapeBounds = getShapeUtils(shape).getBounds(shape)
46
+        //   console.log(shapeBounds, viewport)
47
+        //   return boundsContain(viewport, shapeBounds)
48
+        // })
49
+        .sort((a, b) => a.childIndex - b.childIndex)
50
+        .map((shape) => shape.id)
51
+    )
20
   }, deepCompareArrays)
52
   }, deepCompareArrays)
21
 
53
 
22
   const isSelecting = useSelector((s) => s.isIn('selecting'))
54
   const isSelecting = useSelector((s) => s.isIn('selecting'))

+ 1
- 1
components/canvas/selected.tsx Ver fichero

12
     return Array.from(data.selectedIds.values())
12
     return Array.from(data.selectedIds.values())
13
   }, deepCompareArrays)
13
   }, deepCompareArrays)
14
 
14
 
15
-  const isSelecting = useSelector((s) => s.isInAny('notPointing', 'pinching'))
15
+  const isSelecting = useSelector((s) => s.isIn('selecting'))
16
 
16
 
17
   if (!isSelecting) return null
17
   if (!isSelecting) return null
18
 
18
 

+ 6
- 6
components/canvas/shape.tsx Ver fichero

49
           {...events}
49
           {...events}
50
         />
50
         />
51
       )}
51
       )}
52
-      {!shape.isHidden && <ReadShape isGroup={isGroup} id={id} style={style} />}
52
+      {!shape.isHidden && <RealShape isGroup={isGroup} id={id} style={style} />}
53
       {isGroup &&
53
       {isGroup &&
54
         shape.children.map((shapeId) => (
54
         shape.children.map((shapeId) => (
55
           <Shape
55
           <Shape
69
   style: Partial<React.SVGProps<SVGUseElement>>
69
   style: Partial<React.SVGProps<SVGUseElement>>
70
 }
70
 }
71
 
71
 
72
-const ReadShape = memo(function RealShape({
72
+const RealShape = memo(function RealShape({
73
   isGroup,
73
   isGroup,
74
   id,
74
   id,
75
   style,
75
   style,
157
   )
157
   )
158
 }
158
 }
159
 
159
 
160
-export { HoverIndicator }
161
-
162
-export default memo(Shape)
163
-
164
 function pp(n: number[]) {
160
 function pp(n: number[]) {
165
   return '[' + n.map((v) => v.toFixed(1)).join(', ') + ']'
161
   return '[' + n.map((v) => v.toFixed(1)).join(', ') + ']'
166
 }
162
 }
163
+
164
+export { HoverIndicator }
165
+
166
+export default memo(Shape)

+ 53
- 0
hooks/useCanvasEvents.ts Ver fichero

1
+import { MutableRefObject, useCallback } from 'react'
2
+import state from 'state'
3
+import { fastBrushSelect, fastDrawUpdate } from 'state/hacks'
4
+import inputs from 'state/inputs'
5
+import { isMobile } from 'utils/utils'
6
+
7
+export default function useCanvasEvents(
8
+  rCanvas: MutableRefObject<SVGGElement>
9
+) {
10
+  const handlePointerDown = useCallback((e: React.PointerEvent) => {
11
+    if (!inputs.canAccept(e.pointerId)) return
12
+    rCanvas.current.setPointerCapture(e.pointerId)
13
+    state.send('POINTED_CANVAS', inputs.pointerDown(e, 'canvas'))
14
+  }, [])
15
+
16
+  const handleTouchStart = useCallback((e: React.TouchEvent) => {
17
+    if (isMobile()) {
18
+      if (e.touches.length === 2) {
19
+        state.send('TOUCH_UNDO')
20
+      } else state.send('TOUCHED_CANVAS')
21
+    }
22
+  }, [])
23
+
24
+  const handlePointerMove = useCallback((e: React.PointerEvent) => {
25
+    if (!inputs.canAccept(e.pointerId)) return
26
+
27
+    if (state.isIn('draw.editing')) {
28
+      fastDrawUpdate(inputs.pointerMove(e))
29
+      return
30
+    }
31
+
32
+    if (state.isIn('brushSelecting')) {
33
+      const info = inputs.pointerMove(e)
34
+      fastBrushSelect(info.point)
35
+      return
36
+    }
37
+
38
+    state.send('MOVED_POINTER', inputs.pointerMove(e))
39
+  }, [])
40
+
41
+  const handlePointerUp = useCallback((e: React.PointerEvent) => {
42
+    if (!inputs.canAccept(e.pointerId)) return
43
+    rCanvas.current.releasePointerCapture(e.pointerId)
44
+    state.send('STOPPED_POINTING', { id: 'canvas', ...inputs.pointerUp(e) })
45
+  }, [])
46
+
47
+  return {
48
+    onPointerDown: handlePointerDown,
49
+    onTouchStart: handleTouchStart,
50
+    onPointerMove: handlePointerMove,
51
+    onPointerUp: handlePointerUp,
52
+  }
53
+}

+ 1
- 0
hooks/useShapeEvents.ts Ver fichero

47
   const handlePointerMove = useCallback(
47
   const handlePointerMove = useCallback(
48
     (e: React.PointerEvent) => {
48
     (e: React.PointerEvent) => {
49
       if (!inputs.canAccept(e.pointerId)) return
49
       if (!inputs.canAccept(e.pointerId)) return
50
+
50
       if (isGroup) {
51
       if (isGroup) {
51
         state.send('MOVED_OVER_GROUP', inputs.pointerEnter(e, id))
52
         state.send('MOVED_OVER_GROUP', inputs.pointerEnter(e, id))
52
       } else {
53
       } else {

+ 29
- 9
hooks/useZoomEvents.ts Ver fichero

3
 import inputs from 'state/inputs'
3
 import inputs from 'state/inputs'
4
 import * as vec from 'utils/vec'
4
 import * as vec from 'utils/vec'
5
 import { useGesture } from 'react-use-gesture'
5
 import { useGesture } from 'react-use-gesture'
6
+import {
7
+  fastBrushSelect,
8
+  fastPanUpdate,
9
+  fastPinchCamera,
10
+  fastZoomUpdate,
11
+} from 'state/hacks'
6
 
12
 
7
 /**
13
 /**
8
  * Capture zoom gestures (pinches, wheels and pans) and send to the state.
14
  * Capture zoom gestures (pinches, wheels and pans) and send to the state.
17
     {
23
     {
18
       onWheel: ({ event, delta }) => {
24
       onWheel: ({ event, delta }) => {
19
         if (event.ctrlKey) {
25
         if (event.ctrlKey) {
20
-          state.send('ZOOMED_CAMERA', {
21
-            delta: delta[1],
22
-            ...inputs.wheel(event as WheelEvent),
23
-          })
26
+          const { point } = inputs.wheel(event as WheelEvent)
27
+          fastZoomUpdate(point, delta[1])
28
+          // state.send('ZOOMED_CAMERA', {
29
+          //   delta: delta[1],
30
+          //   ...inputs.wheel(event as WheelEvent),
31
+          // })
32
+          return
33
+        }
34
+
35
+        if (state.isIn('pointing')) {
36
+          fastPanUpdate(delta)
24
           return
37
           return
25
         }
38
         }
26
 
39
 
45
 
58
 
46
         const [distanceDelta, angleDelta] = vec.sub(rPinchDa.current, da)
59
         const [distanceDelta, angleDelta] = vec.sub(rPinchDa.current, da)
47
 
60
 
48
-        state.send('PINCHED', {
49
-          delta: vec.sub(rPinchPoint.current, origin),
50
-          point: origin,
61
+        fastPinchCamera(
62
+          origin,
63
+          vec.sub(rPinchPoint.current, origin),
51
           distanceDelta,
64
           distanceDelta,
52
-          angleDelta,
53
-        })
65
+          angleDelta
66
+        )
67
+
68
+        // state.send('PINCHED', {
69
+        //   delta: vec.sub(rPinchPoint.current, origin),
70
+        //   point: origin,
71
+        //   distanceDelta,
72
+        //   angleDelta,
73
+        // })
54
 
74
 
55
         rPinchDa.current = da
75
         rPinchDa.current = da
56
         rPinchPoint.current = origin
76
         rPinchPoint.current = origin

+ 1
- 1
package.json Ver fichero

16
     "@radix-ui/react-icons": "^1.0.3",
16
     "@radix-ui/react-icons": "^1.0.3",
17
     "@radix-ui/react-radio-group": "^0.0.16",
17
     "@radix-ui/react-radio-group": "^0.0.16",
18
     "@radix-ui/react-tooltip": "^0.0.18",
18
     "@radix-ui/react-tooltip": "^0.0.18",
19
-    "@state-designer/react": "^1.7.1",
19
+    "@state-designer/react": "^1.7.3",
20
     "@stitches/react": "^0.1.9",
20
     "@stitches/react": "^0.1.9",
21
     "framer-motion": "^4.1.16",
21
     "framer-motion": "^4.1.16",
22
     "ismobilejs": "^1.1.1",
22
     "ismobilejs": "^1.1.1",

+ 94
- 0
state/hacks.ts Ver fichero

1
+import { PointerInfo } from 'types'
2
+import {
3
+  getCameraZoom,
4
+  getCurrentCamera,
5
+  screenToWorld,
6
+  setZoomCSS,
7
+} from 'utils/utils'
8
+import session from './session'
9
+import state from './state'
10
+import * as vec from 'utils/vec'
11
+
12
+/**
13
+ * While a user is drawing with the draw tool, we want to update the shape without
14
+ * going through the trouble of updating the entire state machine. Speciifcally, we
15
+ * do not want to push the change through immer. Instead, we'll push the change
16
+ * directly to the state using `forceData`.
17
+ * @param info
18
+ */
19
+export function fastDrawUpdate(info: PointerInfo) {
20
+  const data = { ...state.data }
21
+
22
+  session.current.update(
23
+    data,
24
+    screenToWorld(info.point, data),
25
+    info.pressure,
26
+    info.shiftKey
27
+  )
28
+
29
+  const selectedId = Array.from(data.selectedIds.values())[0]
30
+
31
+  const shape = data.document.pages[data.currentPageId].shapes[selectedId]
32
+
33
+  data.document.pages[data.currentPageId].shapes[selectedId] = { ...shape }
34
+
35
+  state.forceData(Object.freeze(data))
36
+}
37
+
38
+export function fastPanUpdate(delta: number[]) {
39
+  const data = { ...state.data }
40
+  const camera = getCurrentCamera(data)
41
+  camera.point = vec.sub(camera.point, vec.div(delta, camera.zoom))
42
+
43
+  data.pageStates[data.currentPageId].camera = { ...camera }
44
+
45
+  state.forceData(Object.freeze(data))
46
+}
47
+
48
+export function fastZoomUpdate(point: number[], delta: number) {
49
+  const data = { ...state.data }
50
+  const camera = getCurrentCamera(data)
51
+
52
+  const next = camera.zoom - (delta / 100) * camera.zoom
53
+
54
+  const p0 = screenToWorld(point, data)
55
+  camera.zoom = getCameraZoom(next)
56
+  const p1 = screenToWorld(point, data)
57
+  camera.point = vec.add(camera.point, vec.sub(p1, p0))
58
+
59
+  data.pageStates[data.currentPageId].camera = { ...camera }
60
+
61
+  state.forceData(Object.freeze(data))
62
+}
63
+
64
+export function fastPinchCamera(
65
+  point: number[],
66
+  delta: number[],
67
+  distanceDelta: number,
68
+  angleDelta: number
69
+) {
70
+  const data = { ...state.data }
71
+  const camera = getCurrentCamera(data)
72
+
73
+  camera.point = vec.sub(camera.point, vec.div(delta, camera.zoom))
74
+
75
+  const next = camera.zoom - (distanceDelta / 300) * camera.zoom
76
+
77
+  const p0 = screenToWorld(point, data)
78
+  camera.zoom = getCameraZoom(next)
79
+  const p1 = screenToWorld(point, data)
80
+  camera.point = vec.add(camera.point, vec.sub(p1, p0))
81
+
82
+  data.pageStates[data.currentPageId].camera = { ...camera }
83
+
84
+  state.forceData(Object.freeze(data))
85
+}
86
+
87
+export function fastBrushSelect(point: number[]) {
88
+  const data = { ...state.data }
89
+  session.current.update(data, screenToWorld(point, data))
90
+
91
+  data.selectedIds = new Set(data.selectedIds)
92
+
93
+  state.forceData(Object.freeze(data))
94
+}

+ 27
- 0
state/session.ts Ver fichero

1
+import { BaseSession } from './sessions'
2
+
3
+class SessionManager {
4
+  private _current?: BaseSession
5
+
6
+  clear() {
7
+    this._current = undefined
8
+    return this
9
+  }
10
+
11
+  setCurrent(session: BaseSession) {
12
+    this._current = session
13
+    return this
14
+  }
15
+
16
+  get current() {
17
+    return this._current
18
+  }
19
+
20
+  set current(session: BaseSession) {
21
+    this._current = session
22
+  }
23
+}
24
+
25
+const session = new SessionManager()
26
+
27
+export default session

+ 2
- 1
state/sessions/brush-session.ts Ver fichero

4
 import { getShapeUtils } from 'lib/shape-utils'
4
 import { getShapeUtils } from 'lib/shape-utils'
5
 import { getBoundsFromPoints, getPage, getShapes } from 'utils/utils'
5
 import { getBoundsFromPoints, getPage, getShapes } from 'utils/utils'
6
 import * as vec from 'utils/vec'
6
 import * as vec from 'utils/vec'
7
+import state from 'state/state'
7
 
8
 
8
 export default class BrushSession extends BaseSession {
9
 export default class BrushSession extends BaseSession {
9
   origin: number[]
10
   origin: number[]
62
   return {
63
   return {
63
     selectedIds: new Set(data.selectedIds),
64
     selectedIds: new Set(data.selectedIds),
64
     shapeHitTests: Object.fromEntries(
65
     shapeHitTests: Object.fromEntries(
65
-      getShapes(current(data))
66
+      getShapes(state.data)
66
         .filter((shape) => shape.type !== ShapeType.Group)
67
         .filter((shape) => shape.type !== ShapeType.Group)
67
         .map((shape) => {
68
         .map((shape) => {
68
           return [
69
           return [

+ 66
- 56
state/state.ts Ver fichero

25
   rotateBounds,
25
   rotateBounds,
26
   getBoundsCenter,
26
   getBoundsCenter,
27
   getDocumentBranch,
27
   getDocumentBranch,
28
+  getCameraZoom,
28
 } from 'utils/utils'
29
 } from 'utils/utils'
29
 import {
30
 import {
30
   Data,
31
   Data,
43
   SizeStyle,
44
   SizeStyle,
44
   ColorStyle,
45
   ColorStyle,
45
 } from 'types'
46
 } from 'types'
47
+import session from './session'
46
 
48
 
47
 const initialData: Data = {
49
 const initialData: Data = {
48
   isReadOnly: false,
50
   isReadOnly: false,
324
               ],
326
               ],
325
               on: {
327
               on: {
326
                 STARTED_PINCHING: { do: 'completeSession', to: 'pinching' },
328
                 STARTED_PINCHING: { do: 'completeSession', to: 'pinching' },
327
-                MOVED_POINTER: 'updateBrushSession',
329
+                // Currently using hacks.fastBrushSelect
330
+                // MOVED_POINTER: 'updateBrushSession',
328
                 PANNED_CAMERA: 'updateBrushSession',
331
                 PANNED_CAMERA: 'updateBrushSession',
329
                 STOPPED_POINTING: { do: 'completeSession', to: 'selecting' },
332
                 STOPPED_POINTING: { do: 'completeSession', to: 'selecting' },
330
                 CANCELLED: { do: 'cancelSession', to: 'selecting' },
333
                 CANCELLED: { do: 'cancelSession', to: 'selecting' },
331
               },
334
               },
332
             },
335
             },
333
-            pinching: {
336
+          },
337
+        },
338
+        pinching: {
339
+          on: {
340
+            // Pinching uses hacks.fastPinchCamera
341
+            // PINCHED: { do: 'pinchCamera' },
342
+          },
343
+          initial: 'selectPinching',
344
+          onExit: { secretlyDo: 'updateZoomCSS' },
345
+          states: {
346
+            selectPinching: {
334
               on: {
347
               on: {
335
-                PINCHED: { do: 'pinchCamera' },
348
+                STOPPED_PINCHING: { to: 'selecting' },
336
               },
349
               },
337
-              initial: 'selectPinching',
338
-              states: {
339
-                selectPinching: {
340
-                  on: {
341
-                    STOPPED_PINCHING: { to: 'selecting' },
342
-                  },
343
-                },
344
-                toolPinching: {
345
-                  on: {
346
-                    STOPPED_PINCHING: { to: 'usingTool.previous' },
347
-                  },
348
-                },
350
+            },
351
+            toolPinching: {
352
+              on: {
353
+                STOPPED_PINCHING: { to: 'usingTool.previous' },
349
               },
354
               },
350
             },
355
             },
351
           },
356
           },
385
                 editing: {
390
                 editing: {
386
                   onEnter: 'startDrawSession',
391
                   onEnter: 'startDrawSession',
387
                   on: {
392
                   on: {
388
-                    STOPPED_POINTING: {
389
-                      do: 'completeSession',
390
-                      to: 'draw.creating',
391
-                    },
392
                     CANCELLED: {
393
                     CANCELLED: {
393
                       do: 'breakSession',
394
                       do: 'breakSession',
394
                       to: 'selecting',
395
                       to: 'selecting',
395
                     },
396
                     },
397
+                    STOPPED_POINTING: {
398
+                      do: 'completeSession',
399
+                      to: 'draw.creating',
400
+                    },
396
                     PRESSED_SHIFT: 'keyUpdateDrawSession',
401
                     PRESSED_SHIFT: 'keyUpdateDrawSession',
397
                     RELEASED_SHIFT: 'keyUpdateDrawSession',
402
                     RELEASED_SHIFT: 'keyUpdateDrawSession',
398
-                    MOVED_POINTER: 'updateDrawSession',
403
+                    // MOVED_POINTER: 'updateDrawSession',
399
                     PANNED_CAMERA: 'updateDrawSession',
404
                     PANNED_CAMERA: 'updateDrawSession',
400
                   },
405
                   },
401
                 },
406
                 },
816
 
821
 
817
     // Shared
822
     // Shared
818
     breakSession(data) {
823
     breakSession(data) {
819
-      session?.cancel(data)
820
-      session = undefined
824
+      session.current?.cancel(data)
825
+      session.clear()
821
       history.disable()
826
       history.disable()
822
       commands.deleteSelected(data)
827
       commands.deleteSelected(data)
823
       history.enable()
828
       history.enable()
824
     },
829
     },
825
     cancelSession(data) {
830
     cancelSession(data) {
826
-      session?.cancel(data)
827
-      session = undefined
831
+      session.current?.cancel(data)
832
+      session.clear()
828
     },
833
     },
829
     completeSession(data) {
834
     completeSession(data) {
830
-      session?.complete(data)
831
-      session = undefined
835
+      session.current?.complete(data)
836
+      session.clear()
832
     },
837
     },
833
 
838
 
834
     // Brushing
839
     // Brushing
835
     startBrushSession(data, payload: PointerInfo) {
840
     startBrushSession(data, payload: PointerInfo) {
836
-      session = new Sessions.BrushSession(
841
+      session.current = new Sessions.BrushSession(
837
         data,
842
         data,
838
         screenToWorld(payload.point, data)
843
         screenToWorld(payload.point, data)
839
       )
844
       )
840
     },
845
     },
841
     updateBrushSession(data, payload: PointerInfo) {
846
     updateBrushSession(data, payload: PointerInfo) {
842
-      session.update(data, screenToWorld(payload.point, data))
847
+      session.current.update(data, screenToWorld(payload.point, data))
843
     },
848
     },
844
 
849
 
845
     // Rotating
850
     // Rotating
846
     startRotateSession(data, payload: PointerInfo) {
851
     startRotateSession(data, payload: PointerInfo) {
847
-      session = new Sessions.RotateSession(
852
+      session.current = new Sessions.RotateSession(
848
         data,
853
         data,
849
         screenToWorld(payload.point, data)
854
         screenToWorld(payload.point, data)
850
       )
855
       )
851
     },
856
     },
852
     keyUpdateRotateSession(data, payload: PointerInfo) {
857
     keyUpdateRotateSession(data, payload: PointerInfo) {
853
-      session.update(
858
+      session.current.update(
854
         data,
859
         data,
855
         screenToWorld(inputs.pointer.point, data),
860
         screenToWorld(inputs.pointer.point, data),
856
         payload.shiftKey
861
         payload.shiftKey
857
       )
862
       )
858
     },
863
     },
859
     updateRotateSession(data, payload: PointerInfo) {
864
     updateRotateSession(data, payload: PointerInfo) {
860
-      session.update(data, screenToWorld(payload.point, data), payload.shiftKey)
865
+      session.current.update(
866
+        data,
867
+        screenToWorld(payload.point, data),
868
+        payload.shiftKey
869
+      )
861
     },
870
     },
862
 
871
 
863
     // Dragging / Translating
872
     // Dragging / Translating
864
     startTranslateSession(data) {
873
     startTranslateSession(data) {
865
-      session = new Sessions.TranslateSession(
874
+      session.current = new Sessions.TranslateSession(
866
         data,
875
         data,
867
         screenToWorld(inputs.pointer.origin, data)
876
         screenToWorld(inputs.pointer.origin, data)
868
       )
877
       )
871
       data,
880
       data,
872
       payload: { shiftKey: boolean; altKey: boolean }
881
       payload: { shiftKey: boolean; altKey: boolean }
873
     ) {
882
     ) {
874
-      session.update(
883
+      session.current.update(
875
         data,
884
         data,
876
         screenToWorld(inputs.pointer.point, data),
885
         screenToWorld(inputs.pointer.point, data),
877
         payload.shiftKey,
886
         payload.shiftKey,
879
       )
888
       )
880
     },
889
     },
881
     updateTranslateSession(data, payload: PointerInfo) {
890
     updateTranslateSession(data, payload: PointerInfo) {
882
-      session.update(
891
+      session.current.update(
883
         data,
892
         data,
884
         screenToWorld(payload.point, data),
893
         screenToWorld(payload.point, data),
885
         payload.shiftKey,
894
         payload.shiftKey,
892
       const shapeId = Array.from(data.selectedIds.values())[0]
901
       const shapeId = Array.from(data.selectedIds.values())[0]
893
       const handleId = payload.target
902
       const handleId = payload.target
894
 
903
 
895
-      session = new Sessions.HandleSession(
904
+      session.current = new Sessions.HandleSession(
896
         data,
905
         data,
897
         shapeId,
906
         shapeId,
898
         handleId,
907
         handleId,
903
       data,
912
       data,
904
       payload: { shiftKey: boolean; altKey: boolean }
913
       payload: { shiftKey: boolean; altKey: boolean }
905
     ) {
914
     ) {
906
-      session.update(
915
+      session.current.update(
907
         data,
916
         data,
908
         screenToWorld(inputs.pointer.point, data),
917
         screenToWorld(inputs.pointer.point, data),
909
         payload.shiftKey,
918
         payload.shiftKey,
911
       )
920
       )
912
     },
921
     },
913
     updateHandleSession(data, payload: PointerInfo) {
922
     updateHandleSession(data, payload: PointerInfo) {
914
-      session.update(
923
+      session.current.update(
915
         data,
924
         data,
916
         screenToWorld(payload.point, data),
925
         screenToWorld(payload.point, data),
917
         payload.shiftKey,
926
         payload.shiftKey,
925
       payload: PointerInfo & { target: Corner | Edge }
934
       payload: PointerInfo & { target: Corner | Edge }
926
     ) {
935
     ) {
927
       const point = screenToWorld(inputs.pointer.origin, data)
936
       const point = screenToWorld(inputs.pointer.origin, data)
928
-      session = new Sessions.TransformSession(data, payload.target, point)
929
-      session =
937
+      session.current =
930
         data.selectedIds.size === 1
938
         data.selectedIds.size === 1
931
           ? new Sessions.TransformSingleSession(data, payload.target, point)
939
           ? new Sessions.TransformSingleSession(data, payload.target, point)
932
           : new Sessions.TransformSession(data, payload.target, point)
940
           : new Sessions.TransformSession(data, payload.target, point)
933
     },
941
     },
934
     startDrawTransformSession(data, payload: PointerInfo) {
942
     startDrawTransformSession(data, payload: PointerInfo) {
935
-      session = new Sessions.TransformSingleSession(
943
+      session.current = new Sessions.TransformSingleSession(
936
         data,
944
         data,
937
         Corner.BottomRight,
945
         Corner.BottomRight,
938
         screenToWorld(payload.point, data),
946
         screenToWorld(payload.point, data),
940
       )
948
       )
941
     },
949
     },
942
     keyUpdateTransformSession(data, payload: PointerInfo) {
950
     keyUpdateTransformSession(data, payload: PointerInfo) {
943
-      session.update(
951
+      session.current.update(
944
         data,
952
         data,
945
         screenToWorld(inputs.pointer.point, data),
953
         screenToWorld(inputs.pointer.point, data),
946
         payload.shiftKey,
954
         payload.shiftKey,
948
       )
956
       )
949
     },
957
     },
950
     updateTransformSession(data, payload: PointerInfo) {
958
     updateTransformSession(data, payload: PointerInfo) {
951
-      session.update(
959
+      session.current.update(
952
         data,
960
         data,
953
         screenToWorld(payload.point, data),
961
         screenToWorld(payload.point, data),
954
         payload.shiftKey,
962
         payload.shiftKey,
958
 
966
 
959
     // Direction
967
     // Direction
960
     startDirectionSession(data, payload: PointerInfo) {
968
     startDirectionSession(data, payload: PointerInfo) {
961
-      session = new Sessions.DirectionSession(
969
+      session.current = new Sessions.DirectionSession(
962
         data,
970
         data,
963
         screenToWorld(inputs.pointer.origin, data)
971
         screenToWorld(inputs.pointer.origin, data)
964
       )
972
       )
965
     },
973
     },
966
     updateDirectionSession(data, payload: PointerInfo) {
974
     updateDirectionSession(data, payload: PointerInfo) {
967
-      session.update(data, screenToWorld(payload.point, data))
975
+      session.current.update(data, screenToWorld(payload.point, data))
968
     },
976
     },
969
 
977
 
970
     // Drawing
978
     // Drawing
971
     startDrawSession(data, payload: PointerInfo) {
979
     startDrawSession(data, payload: PointerInfo) {
972
       const id = Array.from(data.selectedIds.values())[0]
980
       const id = Array.from(data.selectedIds.values())[0]
973
-      session = new Sessions.DrawSession(
981
+      session.current = new Sessions.DrawSession(
974
         data,
982
         data,
975
         id,
983
         id,
976
         screenToWorld(inputs.pointer.origin, data),
984
         screenToWorld(inputs.pointer.origin, data),
978
       )
986
       )
979
     },
987
     },
980
     keyUpdateDrawSession(data, payload: PointerInfo) {
988
     keyUpdateDrawSession(data, payload: PointerInfo) {
981
-      session.update(
989
+      session.current.update(
982
         data,
990
         data,
983
         screenToWorld(inputs.pointer.point, data),
991
         screenToWorld(inputs.pointer.point, data),
984
         payload.pressure,
992
         payload.pressure,
986
       )
994
       )
987
     },
995
     },
988
     updateDrawSession(data, payload: PointerInfo) {
996
     updateDrawSession(data, payload: PointerInfo) {
989
-      session.update(
997
+      session.current.update(
990
         data,
998
         data,
991
         screenToWorld(payload.point, data),
999
         screenToWorld(payload.point, data),
992
         payload.pressure,
1000
         payload.pressure,
997
     // Arrow
1005
     // Arrow
998
     startArrowSession(data, payload: PointerInfo) {
1006
     startArrowSession(data, payload: PointerInfo) {
999
       const id = Array.from(data.selectedIds.values())[0]
1007
       const id = Array.from(data.selectedIds.values())[0]
1000
-      session = new Sessions.ArrowSession(
1008
+      session.current = new Sessions.ArrowSession(
1001
         data,
1009
         data,
1002
         id,
1010
         id,
1003
         screenToWorld(inputs.pointer.origin, data),
1011
         screenToWorld(inputs.pointer.origin, data),
1005
       )
1013
       )
1006
     },
1014
     },
1007
     keyUpdateArrowSession(data, payload: PointerInfo) {
1015
     keyUpdateArrowSession(data, payload: PointerInfo) {
1008
-      session.update(
1016
+      session.current.update(
1009
         data,
1017
         data,
1010
         screenToWorld(inputs.pointer.point, data),
1018
         screenToWorld(inputs.pointer.point, data),
1011
         payload.shiftKey
1019
         payload.shiftKey
1012
       )
1020
       )
1013
     },
1021
     },
1014
     updateArrowSession(data, payload: PointerInfo) {
1022
     updateArrowSession(data, payload: PointerInfo) {
1015
-      session.update(data, screenToWorld(payload.point, data), payload.shiftKey)
1023
+      session.current.update(
1024
+        data,
1025
+        screenToWorld(payload.point, data),
1026
+        payload.shiftKey
1027
+      )
1016
     },
1028
     },
1017
 
1029
 
1018
     // Nudges
1030
     // Nudges
1257
       const camera = getCurrentCamera(data)
1269
       const camera = getCurrentCamera(data)
1258
       camera.point = vec.sub(camera.point, vec.div(payload.delta, camera.zoom))
1270
       camera.point = vec.sub(camera.point, vec.div(payload.delta, camera.zoom))
1259
     },
1271
     },
1272
+    updateZoomCSS(data) {
1273
+      const camera = getCurrentCamera(data)
1274
+      setZoomCSS(camera.zoom)
1275
+    },
1260
     pinchCamera(
1276
     pinchCamera(
1261
       data,
1277
       data,
1262
       payload: {
1278
       payload: {
1509
   },
1525
   },
1510
 })
1526
 })
1511
 
1527
 
1512
-let session: Sessions.BaseSession
1513
-
1514
 export default state
1528
 export default state
1515
 
1529
 
1516
 export const useSelector = createSelectorHook(state)
1530
 export const useSelector = createSelectorHook(state)
1517
 
1531
 
1518
-function getCameraZoom(zoom: number) {
1519
-  return clamp(zoom, 0.1, 5)
1520
-}
1521
-
1522
 function getParentId(data: Data, id: string) {
1532
 function getParentId(data: Data, id: string) {
1523
   const shape = getPage(data).shapes[id]
1533
   const shape = getPage(data).shapes[id]
1524
   return shape.parentId
1534
   return shape.parentId

+ 8
- 9
types.ts Ver fichero

33
     pages: Record<string, Page>
33
     pages: Record<string, Page>
34
     code: Record<string, CodeFile>
34
     code: Record<string, CodeFile>
35
   }
35
   }
36
-  pageStates: Record<
37
-    string,
38
-    {
39
-      camera: {
40
-        point: number[]
41
-        zoom: number
42
-      }
43
-    }
44
-  >
36
+  pageStates: Record<string, PageState>
45
 }
37
 }
46
 
38
 
47
 /* -------------------------------------------------- */
39
 /* -------------------------------------------------- */
56
   shapes: Record<string, Shape>
48
   shapes: Record<string, Shape>
57
 }
49
 }
58
 
50
 
51
+export interface PageState {
52
+  camera: {
53
+    point: number[]
54
+    zoom: number
55
+  }
56
+}
57
+
59
 export enum ShapeType {
58
 export enum ShapeType {
60
   Dot = 'dot',
59
   Dot = 'dot',
61
   Circle = 'circle',
60
   Circle = 'circle',

+ 4
- 0
utils/utils.ts Ver fichero

834
   }
834
   }
835
 }
835
 }
836
 
836
 
837
+export function getCameraZoom(zoom: number) {
838
+  return clamp(zoom, 0.1, 5)
839
+}
840
+
837
 export function pointInRect(
841
 export function pointInRect(
838
   point: number[],
842
   point: number[],
839
   minX: number,
843
   minX: number,

+ 505
- 404
yarn.lock
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero


Loading…
Cancelar
Guardar