Pārlūkot izejas kodu

Adds direction session

main
Steve Ruiz 4 gadus atpakaļ
vecāks
revīzija
8a650a99d6

+ 7
- 7
components/toolbar.tsx Parādīt failu

@@ -6,13 +6,13 @@ export default function Toolbar() {
6 6
   const activeTool = useSelector((state) =>
7 7
     state.whenIn({
8 8
       selecting: "select",
9
-      creatingDot: "dot",
10
-      creatingCircle: "circle",
11
-      creatingEllipse: "ellipse",
12
-      creatingRay: "ray",
13
-      creatingLine: "line",
14
-      creatingPolyline: "polyline",
15
-      creatingRectangle: "rectangle",
9
+      dot: "dot",
10
+      circle: "circle",
11
+      ellipse: "ellipse",
12
+      ray: "ray",
13
+      line: "line",
14
+      polyline: "polyline",
15
+      rectangle: "rectangle",
16 16
     })
17 17
   )
18 18
 

+ 0
- 4
lib/shapes/circle.tsx Parādīt failu

@@ -87,10 +87,6 @@ const circle = createShape<CircleShape>({
87 87
     return shape
88 88
   },
89 89
 
90
-  stretch(shape, scaleX, scaleY) {
91
-    return shape
92
-  },
93
-
94 90
   transform(shape, bounds, { anchor }) {
95 91
     // Set the new corner or position depending on the anchor
96 92
     switch (anchor) {

+ 2
- 6
lib/shapes/dot.tsx Parādīt failu

@@ -66,16 +66,12 @@ const dot = createShape<DotShape>({
66 66
     return shape
67 67
   },
68 68
 
69
-  translate(shape, delta) {
70
-    shape.point = vec.add(shape.point, delta)
71
-    return shape
72
-  },
73
-
74 69
   scale(shape, scale: number) {
75 70
     return shape
76 71
   },
77 72
 
78
-  stretch(shape, scaleX: number, scaleY: number) {
73
+  translate(shape, delta) {
74
+    shape.point = vec.add(shape.point, delta)
79 75
     return shape
80 76
   },
81 77
 

+ 0
- 4
lib/shapes/ellipse.tsx Parādīt failu

@@ -93,10 +93,6 @@ const ellipse = createShape<EllipseShape>({
93 93
     return shape
94 94
   },
95 95
 
96
-  stretch(shape, scaleX: number, scaleY: number) {
97
-    return shape
98
-  },
99
-
100 96
   transform(shape, bounds) {
101 97
     shape.point = [bounds.minX, bounds.minY]
102 98
     shape.radiusX = bounds.width / 2

+ 0
- 3
lib/shapes/index.tsx Parādīt failu

@@ -67,9 +67,6 @@ export interface ShapeUtility<K extends Shape> {
67 67
   // Apply a scale to a shape.
68 68
   scale(this: ShapeUtility<K>, shape: K, scale: number): K
69 69
 
70
-  // Apply a stretch to a shape.
71
-  stretch(this: ShapeUtility<K>, shape: K, scaleX: number, scaleY: number): K
72
-
73 70
   // Render a shape to JSX.
74 71
   render(this: ShapeUtility<K>, shape: K): JSX.Element
75 72
 

+ 0
- 4
lib/shapes/line.tsx Parādīt failu

@@ -84,10 +84,6 @@ const line = createShape<LineShape>({
84 84
     return shape
85 85
   },
86 86
 
87
-  stretch(shape, scaleX: number, scaleY: number) {
88
-    return shape
89
-  },
90
-
91 87
   transform(shape, bounds) {
92 88
     shape.point = [bounds.minX, bounds.minY]
93 89
 

+ 0
- 4
lib/shapes/polyline.tsx Parādīt failu

@@ -98,10 +98,6 @@ const polyline = createShape<PolylineShape>({
98 98
     return shape
99 99
   },
100 100
 
101
-  stretch(shape, scaleX: number, scaleY: number) {
102
-    return shape
103
-  },
104
-
105 101
   transform(
106 102
     shape,
107 103
     bounds,

+ 7
- 6
lib/shapes/ray.tsx Parādīt failu

@@ -17,9 +17,12 @@ const ray = createShape<RayShape>({
17 17
       parentId: "page0",
18 18
       childIndex: 0,
19 19
       point: [0, 0],
20
-      direction: [0, 0],
20
+      direction: [0, 1],
21 21
       rotation: 0,
22
-      style: {},
22
+      style: {
23
+        stroke: "#000",
24
+        strokeWidth: 1,
25
+      },
23 26
       ...props,
24 27
     }
25 28
   },
@@ -83,11 +86,9 @@ const ray = createShape<RayShape>({
83 86
     return shape
84 87
   },
85 88
 
86
-  stretch(shape, scaleX: number, scaleY: number) {
87
-    return shape
88
-  },
89
-
90 89
   transform(shape, bounds) {
90
+    shape.point = [bounds.minX, bounds.minY]
91
+
91 92
     return shape
92 93
   },
93 94
 

+ 36
- 0
state/commands/direction.ts Parādīt failu

@@ -0,0 +1,36 @@
1
+import Command from "./command"
2
+import history from "../history"
3
+import { DirectionSnapshot } from "state/sessions/direction-session"
4
+import { Data, LineShape, RayShape } from "types"
5
+
6
+export default function translateCommand(
7
+  data: Data,
8
+  before: DirectionSnapshot,
9
+  after: DirectionSnapshot
10
+) {
11
+  history.execute(
12
+    data,
13
+    new Command({
14
+      name: "set_direction",
15
+      category: "canvas",
16
+      do(data) {
17
+        const { shapes } = data.document.pages[after.currentPageId]
18
+
19
+        for (let { id, direction } of after.shapes) {
20
+          const shape = shapes[id] as RayShape | LineShape
21
+
22
+          shape.direction = direction
23
+        }
24
+      },
25
+      undo(data) {
26
+        const { shapes } = data.document.pages[before.currentPageId]
27
+
28
+        for (let { id, direction } of after.shapes) {
29
+          const shape = shapes[id] as RayShape | LineShape
30
+
31
+          shape.direction = direction
32
+        }
33
+      },
34
+    })
35
+  )
36
+}

+ 8
- 1
state/commands/index.ts Parādīt failu

@@ -2,7 +2,14 @@ import translate from "./translate"
2 2
 import transform from "./transform"
3 3
 import generateShapes from "./generate-shapes"
4 4
 import createShape from "./create-shape"
5
+import direction from "./direction"
5 6
 
6
-const commands = { translate, transform, generateShapes, createShape }
7
+const commands = {
8
+  translate,
9
+  transform,
10
+  generateShapes,
11
+  createShape,
12
+  direction,
13
+}
7 14
 
8 15
 export default commands

+ 71
- 0
state/sessions/direction-session.ts Parādīt failu

@@ -0,0 +1,71 @@
1
+import { Data, LineShape, RayShape } from "types"
2
+import * as vec from "utils/vec"
3
+import BaseSession from "./base-session"
4
+import commands from "state/commands"
5
+import { current } from "immer"
6
+
7
+export default class DirectionSession extends BaseSession {
8
+  delta = [0, 0]
9
+  origin: number[]
10
+  snapshot: DirectionSnapshot
11
+
12
+  constructor(data: Data, point: number[]) {
13
+    super(data)
14
+    this.origin = point
15
+    this.snapshot = getDirectionSnapshot(data)
16
+  }
17
+
18
+  update(data: Data, point: number[]) {
19
+    const { currentPageId, shapes } = this.snapshot
20
+    const { document } = data
21
+
22
+    for (let { id } of shapes) {
23
+      const shape = document.pages[currentPageId].shapes[id] as
24
+        | RayShape
25
+        | LineShape
26
+
27
+      shape.direction = vec.uni(vec.vec(shape.point, point))
28
+    }
29
+  }
30
+
31
+  cancel(data: Data) {
32
+    const { document } = data
33
+
34
+    for (let { id, direction } of this.snapshot.shapes) {
35
+      const shape = document.pages[this.snapshot.currentPageId].shapes[id] as
36
+        | RayShape
37
+        | LineShape
38
+
39
+      shape.direction = direction
40
+    }
41
+  }
42
+
43
+  complete(data: Data) {
44
+    commands.direction(data, this.snapshot, getDirectionSnapshot(data))
45
+  }
46
+}
47
+
48
+export function getDirectionSnapshot(data: Data) {
49
+  const {
50
+    document: { pages },
51
+    currentPageId,
52
+  } = current(data)
53
+
54
+  const { shapes } = pages[currentPageId]
55
+
56
+  let snapshapes: { id: string; direction: number[] }[] = []
57
+
58
+  data.selectedIds.forEach((id) => {
59
+    const shape = shapes[id]
60
+    if ("direction" in shape) {
61
+      snapshapes.push({ id: shape.id, direction: shape.direction })
62
+    }
63
+  })
64
+
65
+  return {
66
+    currentPageId,
67
+    shapes: snapshapes,
68
+  }
69
+}
70
+
71
+export type DirectionSnapshot = ReturnType<typeof getDirectionSnapshot>

+ 8
- 1
state/sessions/index.ts Parādīt failu

@@ -2,5 +2,12 @@ import BaseSession from "./base-session"
2 2
 import BrushSession from "./brush-session"
3 3
 import TranslateSession from "./translate-session"
4 4
 import TransformSession from "./transform-session"
5
+import DirectionSession from "./direction-session"
5 6
 
6
-export { BrushSession, BaseSession, TranslateSession, TransformSession }
7
+export {
8
+  BrushSession,
9
+  BaseSession,
10
+  TranslateSession,
11
+  TransformSession,
12
+  DirectionSession,
13
+}

+ 105
- 52
state/state.ts Parādīt failu

@@ -44,13 +44,13 @@ const state = createState({
44 44
       do: "panCamera",
45 45
     },
46 46
     SELECTED_SELECT_TOOL: { to: "selecting" },
47
-    SELECTED_DOT_TOOL: { unless: "isReadOnly", to: "creatingDot" },
48
-    SELECTED_CIRCLE_TOOL: { unless: "isReadOnly", to: "creatingCircle" },
49
-    SELECTED_ELLIPSE_TOOL: { unless: "isReadOnly", to: "creatingEllipse" },
50
-    SELECTED_RAY_TOOL: { unless: "isReadOnly", to: "creatingRay" },
51
-    SELECTED_LINE_TOOL: { unless: "isReadOnly", to: "creatingLine" },
52
-    SELECTED_POLYLINE_TOOL: { unless: "isReadOnly", to: "creatingPolyline" },
53
-    SELECTED_RECTANGLE_TOOL: { unless: "isReadOnly", to: "creatingRectangle" },
47
+    SELECTED_DOT_TOOL: { unless: "isReadOnly", to: "dot" },
48
+    SELECTED_CIRCLE_TOOL: { unless: "isReadOnly", to: "circle" },
49
+    SELECTED_ELLIPSE_TOOL: { unless: "isReadOnly", to: "ellipse" },
50
+    SELECTED_RAY_TOOL: { unless: "isReadOnly", to: "ray" },
51
+    SELECTED_LINE_TOOL: { unless: "isReadOnly", to: "line" },
52
+    SELECTED_POLYLINE_TOOL: { unless: "isReadOnly", to: "polyline" },
53
+    SELECTED_RECTANGLE_TOOL: { unless: "isReadOnly", to: "rectangle" },
54 54
   },
55 55
   initial: "selecting",
56 56
   states: {
@@ -154,18 +154,18 @@ const state = createState({
154 154
         },
155 155
       },
156 156
     },
157
-    creatingDot: {
157
+    dot: {
158 158
       initial: "creating",
159 159
       states: {
160 160
         creating: {
161 161
           on: {
162 162
             POINTED_CANVAS: {
163 163
               do: "createDot",
164
-              to: "creatingDot.positioning",
164
+              to: "dot.editing",
165 165
             },
166 166
           },
167 167
         },
168
-        positioning: {
168
+        editing: {
169 169
           onEnter: "startTranslateSession",
170 170
           on: {
171 171
             MOVED_POINTER: "updateTranslateSession",
@@ -179,12 +179,36 @@ const state = createState({
179 179
         },
180 180
       },
181 181
     },
182
-    creatingCircle: {},
183
-    creatingEllipse: {},
184
-    creatingRay: {},
185
-    creatingLine: {},
186
-    creatingPolyline: {},
187
-    creatingRectangle: {},
182
+    circle: {},
183
+    ellipse: {},
184
+    ray: {
185
+      initial: "creating",
186
+      states: {
187
+        creating: {
188
+          on: {
189
+            POINTED_CANVAS: {
190
+              do: "createRay",
191
+              to: "ray.editing",
192
+            },
193
+          },
194
+        },
195
+        editing: {
196
+          onEnter: "startDirectionSession",
197
+          on: {
198
+            MOVED_POINTER: "updateDirectionSession",
199
+            PANNED_CAMERA: "updateDirectionSession",
200
+            STOPPED_POINTING: { do: "completeSession", to: "selecting" },
201
+            CANCELLED: {
202
+              do: ["cancelSession", "deleteSelectedIds"],
203
+              to: "selecting",
204
+            },
205
+          },
206
+        },
207
+      },
208
+    },
209
+    line: {},
210
+    polyline: {},
211
+    rectangle: {},
188 212
   },
189 213
   conditions: {
190 214
     isPointingBounds(data, payload: PointerInfo) {
@@ -216,41 +240,31 @@ const state = createState({
216 240
     },
217 241
   },
218 242
   actions: {
219
-    // Shapes
243
+    /* --------------------- Shapes --------------------- */
244
+
245
+    // Dot
220 246
     createDot(data, payload: PointerInfo) {
221 247
       const shape = shapeUtilityMap[ShapeType.Dot].create({
222 248
         point: screenToWorld(payload.point, data),
223 249
       })
224 250
 
225 251
       commands.createShape(data, shape)
252
+      data.selectedIds.add(shape.id)
226 253
     },
227 254
 
228
-    // History
229
-    enableHistory() {
230
-      history.enable()
231
-    },
232
-    disableHistory() {
233
-      history.disable()
234
-    },
235
-    undo(data) {
236
-      history.undo(data)
237
-    },
238
-    redo(data) {
239
-      history.redo(data)
240
-    },
255
+    // Ray
256
+    createRay(data, payload: PointerInfo) {
257
+      const shape = shapeUtilityMap[ShapeType.Ray].create({
258
+        point: screenToWorld(payload.point, data),
259
+      })
241 260
 
242
-    // Code
243
-    setGeneratedShapes(data, payload: { shapes: Shape[] }) {
244
-      commands.generateShapes(data, data.currentPageId, payload.shapes)
245
-    },
246
-    increaseCodeFontSize(data) {
247
-      data.settings.fontSize++
248
-    },
249
-    decreaseCodeFontSize(data) {
250
-      data.settings.fontSize--
261
+      commands.createShape(data, shape)
262
+      data.selectedIds.add(shape.id)
251 263
     },
252 264
 
253
-    // Sessions
265
+    /* -------------------- Sessions -------------------- */
266
+
267
+    // Shared
254 268
     cancelSession(data) {
255 269
       session.cancel(data)
256 270
       session = undefined
@@ -297,20 +311,19 @@ const state = createState({
297 311
       session.update(data, screenToWorld(payload.point, data))
298 312
     },
299 313
 
300
-    // Selection
301
-    deleteSelectedIds(data) {
302
-      const { document, currentPageId } = data
303
-      const shapes = document.pages[currentPageId].shapes
314
+    // Direction
315
+    startDirectionSession(data, payload: PointerInfo) {
316
+      session = new Sessions.DirectionSession(
317
+        data,
318
+        screenToWorld(payload.point, data)
319
+      )
320
+    },
321
+    updateDirectionSession(data, payload: PointerInfo) {
322
+      session.update(data, screenToWorld(payload.point, data))
323
+    },
304 324
 
305
-      data.selectedIds.forEach((id) => {
306
-        delete shapes[id]
307
-        // TODO: recursively delete children
308
-      })
325
+    /* -------------------- Selection ------------------- */
309 326
 
310
-      data.selectedIds.clear()
311
-      data.hoveredId = undefined
312
-      data.pointedId = undefined
313
-    },
314 327
     setHoveredId(data, payload: PointerInfo) {
315 328
       data.hoveredId = payload.target
316 329
     },
@@ -357,6 +370,46 @@ const state = createState({
357 370
         vec.div(payload.delta, camera.zoom)
358 371
       )
359 372
     },
373
+    deleteSelectedIds(data) {
374
+      const { document, currentPageId } = data
375
+      const shapes = document.pages[currentPageId].shapes
376
+
377
+      data.selectedIds.forEach((id) => {
378
+        delete shapes[id]
379
+        // TODO: recursively delete children
380
+      })
381
+
382
+      data.selectedIds.clear()
383
+      data.hoveredId = undefined
384
+      data.pointedId = undefined
385
+    },
386
+
387
+    /* ---------------------- Misc ---------------------- */
388
+
389
+    // History
390
+    enableHistory() {
391
+      history.enable()
392
+    },
393
+    disableHistory() {
394
+      history.disable()
395
+    },
396
+    undo(data) {
397
+      history.undo(data)
398
+    },
399
+    redo(data) {
400
+      history.redo(data)
401
+    },
402
+
403
+    // Code
404
+    setGeneratedShapes(data, payload: { shapes: Shape[] }) {
405
+      commands.generateShapes(data, data.currentPageId, payload.shapes)
406
+    },
407
+    increaseCodeFontSize(data) {
408
+      data.settings.fontSize++
409
+    },
410
+    decreaseCodeFontSize(data) {
411
+      data.settings.fontSize--
412
+    },
360 413
   },
361 414
   values: {
362 415
     selectedIds(data) {

Notiek ielāde…
Atcelt
Saglabāt