tldraw/state/sessions/rotate-session.ts

107 lines
2.6 KiB
TypeScript
Raw Normal View History

2021-05-28 16:25:43 +00:00
import { Data } from 'types'
import * as vec from 'utils/vec'
import BaseSession from './base-session'
import commands from 'state/commands'
import { current } from 'immer'
import {
2021-05-23 08:30:20 +00:00
clampToRotationToSegments,
getBoundsCenter,
getCommonBounds,
getPage,
getSelectedShapes,
getShapeBounds,
2021-05-28 16:25:43 +00:00
} from 'utils/utils'
import { getShapeUtils } from 'lib/shape-utils'
const PI2 = Math.PI * 2
2021-05-17 21:27:18 +00:00
export default class RotateSession extends BaseSession {
delta = [0, 0]
origin: number[]
snapshot: RotateSnapshot
constructor(data: Data, point: number[]) {
super(data)
this.origin = point
this.snapshot = getRotateSnapshot(data)
}
update(data: Data, point: number[], isLocked: boolean) {
const { boundsCenter, shapes } = this.snapshot
2021-05-17 21:27:18 +00:00
const page = getPage(data)
2021-05-18 08:32:20 +00:00
const a1 = vec.angle(boundsCenter, this.origin)
const a2 = vec.angle(boundsCenter, point)
2021-05-17 21:27:18 +00:00
2021-05-23 08:30:20 +00:00
let rot = a2 - a1
if (isLocked) {
2021-05-23 08:30:20 +00:00
rot = clampToRotationToSegments(rot, 24)
}
data.boundsRotation = (PI2 + (this.snapshot.boundsRotation + rot)) % PI2
2021-05-18 08:32:20 +00:00
for (let { id, center, offset, rotation } of shapes) {
const shape = page.shapes[id]
getShapeUtils(shape)
2021-05-25 17:52:02 +00:00
.rotateTo(
shape,
(PI2 +
(isLocked
? clampToRotationToSegments(rotation + rot, 24)
: rotation + rot)) %
PI2
)
2021-05-25 11:38:21 +00:00
.translateTo(
shape,
vec.sub(vec.rotWith(center, boundsCenter, rot % PI2), offset)
)
2021-05-17 21:27:18 +00:00
}
}
cancel(data: Data) {
const page = getPage(data, this.snapshot.currentPageId)
2021-05-17 21:27:18 +00:00
2021-05-18 08:32:20 +00:00
for (let { id, point, rotation } of this.snapshot.shapes) {
const shape = page.shapes[id]
2021-05-25 11:38:21 +00:00
getShapeUtils(shape).rotateTo(shape, rotation).translateTo(shape, point)
2021-05-17 21:27:18 +00:00
}
}
complete(data: Data) {
commands.rotate(data, this.snapshot, getRotateSnapshot(data))
}
}
export function getRotateSnapshot(data: Data) {
const shapes = getSelectedShapes(current(data))
2021-05-17 21:27:18 +00:00
const shapesBounds = Object.fromEntries(
shapes.map((shape) => [shape.id, getShapeBounds(shape)])
2021-05-17 21:27:18 +00:00
)
const bounds = getCommonBounds(...Object.values(shapesBounds))
return {
currentPageId: data.currentPageId,
boundsRotation: data.boundsRotation,
2021-05-25 17:52:02 +00:00
boundsCenter: getBoundsCenter(bounds),
2021-05-18 08:32:20 +00:00
shapes: shapes.map(({ id, point, rotation }) => {
const bounds = shapesBounds[id]
const offset = [bounds.width / 2, bounds.height / 2]
const center = getBoundsCenter(bounds)
2021-05-18 08:32:20 +00:00
return {
id,
point,
rotation,
offset,
center,
}
}),
2021-05-17 21:27:18 +00:00
}
}
export type RotateSnapshot = ReturnType<typeof getRotateSnapshot>