Browse Source

Fixes brushing, selection, double-clicking

main
Steve Ruiz 4 years ago
parent
commit
c48537121f
4 changed files with 128 additions and 100 deletions
  1. 2
    2
      hooks/useShapeEvents.ts
  2. 26
    15
      state/sessions/brush-session.ts
  3. 96
    83
      state/state.ts
  4. 4
    0
      utils/utils.ts

+ 2
- 2
hooks/useShapeEvents.ts View File

@@ -13,11 +13,11 @@ export default function useShapeEvents(
13 13
       if (!inputs.canAccept(e.pointerId)) return
14 14
       e.stopPropagation()
15 15
       rGroup.current.setPointerCapture(e.pointerId)
16
+
16 17
       if (inputs.isDoubleClick()) {
17 18
         state.send('DOUBLE_POINTED_SHAPE', inputs.pointerDown(e, id))
18
-      } else {
19
-        state.send('POINTED_SHAPE', inputs.pointerDown(e, id))
20 19
       }
20
+      state.send('POINTED_SHAPE', inputs.pointerDown(e, id))
21 21
     },
22 22
     [id]
23 23
   )

+ 26
- 15
state/sessions/brush-session.ts View File

@@ -5,7 +5,7 @@ import { getShapeUtils } from 'lib/shape-utils'
5 5
 import {
6 6
   getBoundsFromPoints,
7 7
   getPage,
8
-  getSelectedIds,
8
+  getPageState,
9 9
   getShapes,
10 10
   setSelectedIds,
11 11
   setToArray,
@@ -32,9 +32,11 @@ export default class BrushSession extends BaseSession {
32 32
 
33 33
     const hits = new Set<string>([])
34 34
 
35
-    const selectedIds = getSelectedIds(data)
35
+    const selectedIds = new Set(snapshot.selectedIds)
36 36
 
37 37
     for (let id in snapshot.shapeHitTests) {
38
+      if (selectedIds.has(id)) continue
39
+
38 40
       const { test, selectId } = snapshot.shapeHitTests[id]
39 41
       if (!hits.has(selectId)) {
40 42
         if (test(brushBounds)) {
@@ -50,6 +52,8 @@ export default class BrushSession extends BaseSession {
50 52
       }
51 53
     }
52 54
 
55
+    getPageState(data).selectedIds = selectedIds
56
+
53 57
     data.brush = brushBounds
54 58
   }
55 59
 
@@ -69,21 +73,28 @@ export default class BrushSession extends BaseSession {
69 73
  * brush will intersect that shape. For tests, start broad -> fine.
70 74
  */
71 75
 export function getBrushSnapshot(data: Data) {
76
+  const cData = current(data)
77
+  const { selectedIds } = getPageState(cData)
78
+
79
+  const shapesToTest = getShapes(cData)
80
+    .filter((shape) => shape.type !== ShapeType.Group)
81
+    .filter(
82
+      (shape) => !(selectedIds.has(shape.id) || selectedIds.has(shape.parentId))
83
+    )
84
+
72 85
   return {
73
-    selectedIds: setToArray(getSelectedIds(data)),
86
+    selectedIds: setToArray(selectedIds),
74 87
     shapeHitTests: Object.fromEntries(
75
-      getShapes(state.data)
76
-        .filter((shape) => shape.type !== ShapeType.Group)
77
-        .map((shape) => {
78
-          return [
79
-            shape.id,
80
-            {
81
-              selectId: getTopParentId(data, shape.id),
82
-              test: (bounds: Bounds) =>
83
-                getShapeUtils(shape).hitTestBounds(shape, bounds),
84
-            },
85
-          ]
86
-        })
88
+      shapesToTest.map((shape) => {
89
+        return [
90
+          shape.id,
91
+          {
92
+            selectId: getTopParentId(cData, shape.id),
93
+            test: (bounds: Bounds) =>
94
+              getShapeUtils(shape).hitTestBounds(shape, bounds),
95
+          },
96
+        ]
97
+      })
87 98
     ),
88 99
   }
89 100
 }

+ 96
- 83
state/state.ts View File

@@ -50,8 +50,6 @@ import {
50 50
 import session from './session'
51 51
 import { pointInBounds } from 'utils/bounds'
52 52
 
53
-let currentBounds: Bounds
54
-
55 53
 const initialData: Data = {
56 54
   isReadOnly: false,
57 55
   settings: {
@@ -212,7 +210,13 @@ const state = createState({
212 210
                 CANCELLED: 'clearSelectedIds',
213 211
                 STARTED_PINCHING: { to: 'pinching' },
214 212
                 POINTED_CANVAS: { to: 'brushSelecting' },
215
-                POINTED_BOUNDS: { to: 'pointingBounds' },
213
+                POINTED_BOUNDS: [
214
+                  {
215
+                    if: 'isPressingMetaKey',
216
+                    to: 'brushSelecting',
217
+                  },
218
+                  { to: 'pointingBounds' },
219
+                ],
216 220
                 POINTED_BOUNDS_HANDLE: {
217 221
                   if: 'isPointingRotationHandle',
218 222
                   to: 'rotatingSelection',
@@ -225,14 +229,20 @@ const state = createState({
225 229
                     unless: 'shapeIsHovered',
226 230
                     do: 'setHoveredId',
227 231
                   },
228
-                  else: { if: 'shapeIsHovered', do: 'clearHoveredId' },
232
+                  else: {
233
+                    if: 'shapeIsHovered',
234
+                    do: 'clearHoveredId',
235
+                  },
229 236
                 },
230 237
                 UNHOVERED_SHAPE: 'clearHoveredId',
231 238
                 DOUBLE_POINTED_SHAPE: [
232
-                  'setDrilledPointedId',
233
-                  'clearSelectedIds',
234
-                  'pushPointedIdToSelectedIds',
235 239
                   {
240
+                    unless: 'isPressingShiftKey',
241
+                    do: [
242
+                      'setDrilledPointedId',
243
+                      'clearSelectedIds',
244
+                      'pushPointedIdToSelectedIds',
245
+                    ],
236 246
                     to: 'pointingBounds',
237 247
                   },
238 248
                 ],
@@ -242,7 +252,10 @@ const state = createState({
242 252
                     to: 'brushSelecting',
243 253
                   },
244 254
                   'setPointedId',
245
-                  { if: 'pointInSelectionBounds', to: 'pointingBounds' },
255
+                  {
256
+                    if: 'pointInSelectionBounds',
257
+                    to: 'pointingBounds',
258
+                  },
246 259
                   {
247 260
                     unless: 'isPointedShapeSelected',
248 261
                     then: {
@@ -262,10 +275,12 @@ const state = createState({
262 275
                 STOPPED_POINTING: [
263 276
                   {
264 277
                     if: 'isPressingShiftKey',
265
-                    then: {
266
-                      if: 'isPointedShapeSelected',
267
-                      do: 'pullPointedIdFromSelectedIds',
268
-                    },
278
+                    then: [
279
+                      {
280
+                        if: 'isPointedShapeSelected',
281
+                        do: 'pullPointedIdFromSelectedIds',
282
+                      },
283
+                    ],
269 284
                     else: {
270 285
                       unless: 'isPointingBounds',
271 286
                       do: ['clearSelectedIds', 'pushPointedIdToSelectedIds'],
@@ -742,7 +757,7 @@ const state = createState({
742 757
   },
743 758
   conditions: {
744 759
     isPointingBounds(data, payload: PointerInfo) {
745
-      return payload.target === 'bounds'
760
+      return getSelectedIds(data).size > 0 && payload.target === 'bounds'
746 761
     },
747 762
     isReadOnly(data) {
748 763
       return data.isReadOnly
@@ -763,9 +778,11 @@ const state = createState({
763 778
       return data.hoveredId === payload.target
764 779
     },
765 780
     pointInSelectionBounds(data, payload: PointerInfo) {
766
-      return (
767
-        currentBounds &&
768
-        pointInBounds(screenToWorld(payload.point, data), currentBounds)
781
+      if (getSelectedIds(data).size === 0) return false
782
+
783
+      return pointInBounds(
784
+        screenToWorld(payload.point, data),
785
+        getSelectionBounds(data)
769 786
       )
770 787
     },
771 788
     pointHitsShape(data, payload: PointerInfo) {
@@ -1448,73 +1465,7 @@ const state = createState({
1448 1465
       return new Set(getSelectedIds(data))
1449 1466
     },
1450 1467
     selectedBounds(data) {
1451
-      const selectedIds = getSelectedIds(data)
1452
-
1453
-      const page = getPage(data)
1454
-
1455
-      const shapes = Array.from(selectedIds.values())
1456
-        .map((id) => page.shapes[id])
1457
-        .filter(Boolean)
1458
-
1459
-      if (selectedIds.size === 0) return null
1460
-
1461
-      if (selectedIds.size === 1) {
1462
-        if (!shapes[0]) {
1463
-          console.error('Could not find that shape! Clearing selected IDs.')
1464
-          setSelectedIds(data, [])
1465
-          return null
1466
-        }
1467
-
1468
-        const shape = shapes[0]
1469
-        const shapeUtils = getShapeUtils(shape)
1470
-
1471
-        if (!shapeUtils.canTransform) return null
1472
-
1473
-        let bounds = shapeUtils.getBounds(shape)
1474
-
1475
-        let parentId = shape.parentId
1476
-
1477
-        while (parentId !== data.currentPageId) {
1478
-          const parent = page.shapes[parentId]
1479
-
1480
-          bounds = rotateBounds(
1481
-            bounds,
1482
-            getBoundsCenter(getShapeUtils(parent).getBounds(parent)),
1483
-            parent.rotation
1484
-          )
1485
-
1486
-          bounds.rotation = parent.rotation
1487
-
1488
-          parentId = parent.parentId
1489
-        }
1490
-
1491
-        return bounds
1492
-      }
1493
-
1494
-      const uniqueSelectedShapeIds: string[] = Array.from(
1495
-        new Set(
1496
-          Array.from(selectedIds.values()).flatMap((id) =>
1497
-            getDocumentBranch(data, id)
1498
-          )
1499
-        ).values()
1500
-      )
1501
-
1502
-      const commonBounds = getCommonBounds(
1503
-        ...uniqueSelectedShapeIds
1504
-          .map((id) => page.shapes[id])
1505
-          .filter((shape) => shape.type !== ShapeType.Group)
1506
-          .map((shape) => {
1507
-            const parentOffset = getParentOffset(data, shape.id)
1508
-            const parentRotation = getParentRotation(data, shape.id)
1509
-            const bounds = getShapeUtils(shape).getRotatedBounds(shape)
1510
-
1511
-            return bounds
1512
-          })
1513
-      )
1514
-
1515
-      currentBounds = commonBounds
1516
-
1517
-      return commonBounds
1468
+      return getSelectionBounds(data)
1518 1469
     },
1519 1470
     selectedStyle(data) {
1520 1471
       const selectedIds = Array.from(getSelectedIds(data).values())
@@ -1591,3 +1542,65 @@ function hasPointedIdInChildren(data: Data, id: string, pointedId: string) {
1591 1542
     hasPointedIdInChildren(data, childId, pointedId)
1592 1543
   )
1593 1544
 }
1545
+
1546
+function getSelectionBounds(data: Data) {
1547
+  const selectedIds = getSelectedIds(data)
1548
+
1549
+  const page = getPage(data)
1550
+
1551
+  const shapes = Array.from(selectedIds.values())
1552
+    .map((id) => page.shapes[id])
1553
+    .filter(Boolean)
1554
+
1555
+  if (selectedIds.size === 0) return null
1556
+
1557
+  if (selectedIds.size === 1) {
1558
+    if (!shapes[0]) {
1559
+      console.error('Could not find that shape! Clearing selected IDs.')
1560
+      setSelectedIds(data, [])
1561
+      return null
1562
+    }
1563
+
1564
+    const shape = shapes[0]
1565
+    const shapeUtils = getShapeUtils(shape)
1566
+
1567
+    if (!shapeUtils.canTransform) return null
1568
+
1569
+    let bounds = shapeUtils.getBounds(shape)
1570
+
1571
+    let parentId = shape.parentId
1572
+
1573
+    while (parentId !== data.currentPageId) {
1574
+      const parent = page.shapes[parentId]
1575
+
1576
+      bounds = rotateBounds(
1577
+        bounds,
1578
+        getBoundsCenter(getShapeUtils(parent).getBounds(parent)),
1579
+        parent.rotation
1580
+      )
1581
+
1582
+      bounds.rotation = parent.rotation
1583
+
1584
+      parentId = parent.parentId
1585
+    }
1586
+
1587
+    return bounds
1588
+  }
1589
+
1590
+  const uniqueSelectedShapeIds: string[] = Array.from(
1591
+    new Set(
1592
+      Array.from(selectedIds.values()).flatMap((id) =>
1593
+        getDocumentBranch(data, id)
1594
+      )
1595
+    ).values()
1596
+  )
1597
+
1598
+  const commonBounds = getCommonBounds(
1599
+    ...uniqueSelectedShapeIds
1600
+      .map((id) => page.shapes[id])
1601
+      .filter((shape) => shape.type !== ShapeType.Group)
1602
+      .map((shape) => getShapeUtils(shape).getRotatedBounds(shape))
1603
+  )
1604
+
1605
+  return commonBounds
1606
+}

+ 4
- 0
utils/utils.ts View File

@@ -1370,6 +1370,10 @@ export function getPage(data: Data, pageId = data.currentPageId) {
1370 1370
   return data.document.pages[pageId]
1371 1371
 }
1372 1372
 
1373
+export function getPageState(data: Data, pageId = data.currentPageId) {
1374
+  return data.pageStates[pageId]
1375
+}
1376
+
1373 1377
 export function getCurrentCode(data: Data, fileId = data.currentCodeFileId) {
1374 1378
   return data.document.code[fileId]
1375 1379
 }

Loading…
Cancel
Save