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.

arrow-session.ts 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { ArrowShape, 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. import {
  7. getBoundsFromPoints,
  8. getPage,
  9. getSelectedIds,
  10. setToArray,
  11. updateParents,
  12. } from 'utils/utils'
  13. import { getShapeUtils } from 'lib/shape-utils'
  14. export default class ArrowSession extends BaseSession {
  15. points: number[][]
  16. origin: number[]
  17. snapshot: ArrowSnapshot
  18. isLocked: boolean
  19. lockedDirection: 'horizontal' | 'vertical'
  20. constructor(data: Data, id: string, point: number[], isLocked: boolean) {
  21. super(data)
  22. this.origin = point
  23. this.points = [[0, 0]]
  24. this.snapshot = getArrowSnapshot(data, id)
  25. }
  26. update(data: Data, point: number[], isLocked = false) {
  27. const { id } = this.snapshot
  28. const delta = vec.vec(this.origin, point)
  29. if (isLocked) {
  30. if (!this.isLocked && this.points.length > 1) {
  31. this.isLocked = true
  32. if (Math.abs(delta[0]) < Math.abs(delta[1])) {
  33. this.lockedDirection = 'vertical'
  34. } else {
  35. this.lockedDirection = 'horizontal'
  36. }
  37. }
  38. } else {
  39. if (this.isLocked) {
  40. this.isLocked = false
  41. }
  42. }
  43. if (this.isLocked) {
  44. if (this.lockedDirection === 'vertical') {
  45. point[0] = this.origin[0]
  46. } else {
  47. point[1] = this.origin[1]
  48. }
  49. }
  50. const shape = getPage(data).shapes[id] as ArrowShape
  51. getShapeUtils(shape).onHandleChange(shape, {
  52. end: {
  53. ...shape.handles.end,
  54. point: vec.sub(point, shape.point),
  55. },
  56. })
  57. updateParents(data, [shape.id])
  58. }
  59. cancel(data: Data) {
  60. const { id, initialShape } = this.snapshot
  61. const shape = getPage(data).shapes[id] as ArrowShape
  62. getShapeUtils(shape)
  63. .onHandleChange(shape, { end: initialShape.handles.end })
  64. .setProperty(shape, 'point', initialShape.point)
  65. updateParents(data, [shape.id])
  66. }
  67. complete(data: Data) {
  68. const { id } = this.snapshot
  69. const shape = getPage(data).shapes[id] as ArrowShape
  70. const { start, end, bend } = shape.handles
  71. // Normalize point and handles
  72. const bounds = getBoundsFromPoints([start.point, end.point])
  73. const corner = [bounds.minX, bounds.minY]
  74. const newPoint = vec.add(shape.point, corner)
  75. const nextHandles = {
  76. start: { ...start, point: vec.sub(start.point, corner) },
  77. end: { ...end, point: vec.sub(end.point, corner) },
  78. bend: { ...bend, point: vec.sub(bend.point, corner) },
  79. }
  80. getShapeUtils(shape)
  81. .setProperty(shape, 'points', [
  82. nextHandles.start.point,
  83. nextHandles.end.point,
  84. ])
  85. .setProperty(shape, 'handles', nextHandles)
  86. .setProperty(shape, 'point', newPoint)
  87. .onHandleChange(shape, nextHandles)
  88. commands.arrow(
  89. data,
  90. this.snapshot,
  91. getArrowSnapshot(data, this.snapshot.id)
  92. )
  93. }
  94. }
  95. export function getArrowSnapshot(data: Data, id: string) {
  96. const initialShape = getPage(current(data)).shapes[id] as ArrowShape
  97. return {
  98. id,
  99. initialShape,
  100. selectedIds: setToArray(getSelectedIds(data)),
  101. currentPageId: data.currentPageId,
  102. }
  103. }
  104. export type ArrowSnapshot = ReturnType<typeof getArrowSnapshot>