Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

rotate-session.ts 2.8KB

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