You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

state.ts 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { createSelectorHook, createState } from "@state-designer/react"
  2. import { clamp, screenToWorld } from "utils/utils"
  3. import * as vec from "utils/vec"
  4. import { Data } from "types"
  5. import { defaultDocument } from "./data"
  6. import * as Sessions from "./sessions"
  7. const initialData: Data = {
  8. camera: {
  9. point: [0, 0],
  10. zoom: 1,
  11. },
  12. brush: undefined,
  13. pointedId: null,
  14. selectedIds: [],
  15. currentPageId: "page0",
  16. document: defaultDocument,
  17. }
  18. const state = createState({
  19. data: initialData,
  20. on: {
  21. ZOOMED_CAMERA: {
  22. do: "zoomCamera",
  23. },
  24. PANNED_CAMERA: {
  25. do: "panCamera",
  26. },
  27. },
  28. initial: "selecting",
  29. states: {
  30. selecting: {
  31. on: {
  32. POINTED_CANVAS: { to: "brushSelecting" },
  33. },
  34. },
  35. brushSelecting: {
  36. onEnter: [
  37. { unless: "isPressingShiftKey", do: "clearSelection" },
  38. "startBrushSession",
  39. ],
  40. on: {
  41. MOVED_POINTER: "updateBrushSession",
  42. PANNED_CAMERA: "updateBrushSession",
  43. STOPPED_POINTING: { do: "completeSession", to: "selecting" },
  44. CANCELLED: { do: "cancelSession", to: "selecting" },
  45. },
  46. },
  47. },
  48. conditions: {
  49. isPressingShiftKey(data, payload: { shiftKey: boolean }) {
  50. return payload.shiftKey
  51. },
  52. },
  53. actions: {
  54. cancelSession(data) {
  55. session.cancel(data)
  56. session = undefined
  57. },
  58. completeSession(data) {
  59. session.complete(data)
  60. session = undefined
  61. },
  62. startBrushSession(data, payload: { point: number[] }) {
  63. session = new Sessions.BrushSession(
  64. data,
  65. screenToWorld(payload.point, data)
  66. )
  67. },
  68. updateBrushSession(data, payload: { point: number[] }) {
  69. session.update(data, screenToWorld(payload.point, data))
  70. },
  71. // Selection
  72. clearSelection(data) {
  73. data.selectedIds = []
  74. },
  75. // Camera
  76. zoomCamera(data, payload: { delta: number; point: number[] }) {
  77. const { camera } = data
  78. const p0 = screenToWorld(payload.point, data)
  79. camera.zoom = clamp(
  80. camera.zoom - (payload.delta / 100) * camera.zoom,
  81. 0.5,
  82. 3
  83. )
  84. const p1 = screenToWorld(payload.point, data)
  85. camera.point = vec.add(camera.point, vec.sub(p1, p0))
  86. },
  87. panCamera(data, payload: { delta: number[]; point: number[] }) {
  88. const { camera } = data
  89. data.camera.point = vec.sub(
  90. camera.point,
  91. vec.div(payload.delta, camera.zoom)
  92. )
  93. },
  94. },
  95. values: {
  96. selectedIds(data) {
  97. return new Set(data.selectedIds)
  98. },
  99. },
  100. })
  101. let session: Sessions.BaseSession
  102. export default state
  103. export const useSelector = createSelectorHook(state)