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.

translate-session.ts 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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 { v4 as uuid } from 'uuid'
  7. import { getChildIndexAbove, getPage, getSelectedShapes } from 'utils/utils'
  8. import { getShapeUtils } from 'lib/shape-utils'
  9. export default class TranslateSession extends BaseSession {
  10. delta = [0, 0]
  11. origin: number[]
  12. snapshot: TranslateSnapshot
  13. isCloning = false
  14. constructor(data: Data, point: number[]) {
  15. super(data)
  16. this.origin = point
  17. this.snapshot = getTranslateSnapshot(data)
  18. }
  19. update(data: Data, point: number[], isAligned: boolean, isCloning: boolean) {
  20. const { currentPageId, clones, initialShapes } = this.snapshot
  21. const { shapes } = getPage(data, currentPageId)
  22. const delta = vec.vec(this.origin, point)
  23. if (isAligned) {
  24. if (Math.abs(delta[0]) < Math.abs(delta[1])) {
  25. delta[0] = 0
  26. } else {
  27. delta[1] = 0
  28. }
  29. }
  30. if (isCloning) {
  31. if (!this.isCloning) {
  32. this.isCloning = true
  33. data.selectedIds.clear()
  34. for (const { id, point } of initialShapes) {
  35. const shape = shapes[id]
  36. getShapeUtils(shape).translateTo(shape, point)
  37. }
  38. for (const clone of clones) {
  39. shapes[clone.id] = { ...clone }
  40. data.selectedIds.add(clone.id)
  41. }
  42. }
  43. for (const { id, point } of clones) {
  44. const shape = shapes[id]
  45. getShapeUtils(shape).translateTo(shape, vec.add(point, delta))
  46. }
  47. } else {
  48. if (this.isCloning) {
  49. this.isCloning = false
  50. data.selectedIds.clear()
  51. for (const { id } of initialShapes) {
  52. data.selectedIds.add(id)
  53. }
  54. for (const clone of clones) {
  55. delete shapes[clone.id]
  56. }
  57. }
  58. for (const { id, point } of initialShapes) {
  59. const shape = shapes[id]
  60. getShapeUtils(shape).translateTo(shape, vec.add(point, delta))
  61. }
  62. }
  63. }
  64. cancel(data: Data) {
  65. const { initialShapes, clones, currentPageId } = this.snapshot
  66. const { shapes } = getPage(data, currentPageId)
  67. for (const { id, point } of initialShapes) {
  68. const shape = shapes[id]
  69. getShapeUtils(shape).translateTo(shape, point)
  70. }
  71. for (const { id } of clones) {
  72. delete shapes[id]
  73. }
  74. }
  75. complete(data: Data) {
  76. if (!this.snapshot.hasUnlockedShapes) return
  77. commands.translate(
  78. data,
  79. this.snapshot,
  80. getTranslateSnapshot(data),
  81. this.isCloning
  82. )
  83. }
  84. }
  85. export function getTranslateSnapshot(data: Data) {
  86. const cData = current(data)
  87. const shapes = getSelectedShapes(cData).filter((shape) => !shape.isLocked)
  88. const hasUnlockedShapes = shapes.length > 0
  89. return {
  90. hasUnlockedShapes,
  91. currentPageId: data.currentPageId,
  92. initialShapes: shapes.map(({ id, point }) => ({ id, point })),
  93. clones: shapes.map((shape) => ({
  94. ...shape,
  95. id: uuid(),
  96. childIndex: getChildIndexAbove(cData, shape.id),
  97. })),
  98. }
  99. }
  100. export type TranslateSnapshot = ReturnType<typeof getTranslateSnapshot>