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.

rotate-session.ts 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import { Data } 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. clampToRotationToSegments,
  8. getBoundsCenter,
  9. getCommonBounds,
  10. getPage,
  11. getSelectedShapes,
  12. getRotatedBounds,
  13. getShapeBounds,
  14. updateParents,
  15. } from 'utils/utils'
  16. import { getShapeUtils } from 'lib/shape-utils'
  17. const PI2 = Math.PI * 2
  18. export default class RotateSession extends BaseSession {
  19. delta = [0, 0]
  20. origin: number[]
  21. snapshot: RotateSnapshot
  22. constructor(data: Data, point: number[]) {
  23. super(data)
  24. this.origin = point
  25. this.snapshot = getRotateSnapshot(data)
  26. }
  27. update(data: Data, point: number[], isLocked: boolean) {
  28. const { commonBoundsCenter, initialShapes } = this.snapshot
  29. const page = getPage(data)
  30. const a1 = vec.angle(commonBoundsCenter, this.origin)
  31. const a2 = vec.angle(commonBoundsCenter, point)
  32. let rot = a2 - a1
  33. if (isLocked) {
  34. rot = clampToRotationToSegments(rot, 24)
  35. }
  36. data.boundsRotation = (PI2 + (this.snapshot.boundsRotation + rot)) % PI2
  37. for (let { id, center, offset, rotation } of initialShapes) {
  38. const shape = page.shapes[id]
  39. // const rotationOffset = vec.sub(
  40. // getBoundsCenter(getShapeBounds(shape)),
  41. // getBoundsCenter(getRotatedBounds(shape))
  42. // )
  43. const nextRotation = isLocked
  44. ? clampToRotationToSegments(rotation + rot, 24)
  45. : rotation + rot
  46. const nextPoint = vec.sub(
  47. vec.rotWith(center, commonBoundsCenter, rot),
  48. offset
  49. )
  50. getShapeUtils(shape)
  51. .setProperty(shape, 'rotation', (PI2 + nextRotation) % PI2)
  52. .setProperty(shape, 'point', nextPoint)
  53. }
  54. updateParents(
  55. data,
  56. initialShapes.map((s) => s.id)
  57. )
  58. }
  59. cancel(data: Data) {
  60. const { currentPageId, initialShapes } = this.snapshot
  61. const page = getPage(data, currentPageId)
  62. for (let { id, point, rotation } of initialShapes) {
  63. const shape = page.shapes[id]
  64. getShapeUtils(shape)
  65. .setProperty(shape, 'rotation', rotation)
  66. .setProperty(shape, 'point', point)
  67. }
  68. updateParents(
  69. data,
  70. initialShapes.map((s) => s.id)
  71. )
  72. }
  73. complete(data: Data) {
  74. if (!this.snapshot.hasUnlockedShapes) return
  75. commands.rotate(data, this.snapshot, getRotateSnapshot(data))
  76. }
  77. }
  78. export function getRotateSnapshot(data: Data) {
  79. const initialShapes = getSelectedShapes(current(data)).filter(
  80. (shape) => !shape.isLocked
  81. )
  82. const hasUnlockedShapes = initialShapes.length > 0
  83. const shapesBounds = Object.fromEntries(
  84. initialShapes.map((shape) => [shape.id, getShapeBounds(shape)])
  85. )
  86. const bounds = getCommonBounds(...Object.values(shapesBounds))
  87. const commonBoundsCenter = getBoundsCenter(bounds)
  88. return {
  89. hasUnlockedShapes,
  90. currentPageId: data.currentPageId,
  91. boundsRotation: data.boundsRotation,
  92. commonBoundsCenter,
  93. initialShapes: initialShapes.map((shape) => {
  94. const bounds = shapesBounds[shape.id]
  95. const center = getBoundsCenter(bounds)
  96. const offset = vec.sub(center, shape.point)
  97. const rotationOffset = vec.sub(
  98. center,
  99. getBoundsCenter(getRotatedBounds(shape))
  100. )
  101. return {
  102. id: shape.id,
  103. point: shape.point,
  104. rotation: shape.rotation,
  105. offset,
  106. rotationOffset,
  107. center,
  108. }
  109. }),
  110. }
  111. }
  112. export type RotateSnapshot = ReturnType<typeof getRotateSnapshot>