tldraw/state/sessions/brush-session.ts

76 lines
1.9 KiB
TypeScript
Raw Normal View History

2021-05-10 12:16:57 +00:00
import { current } from "immer"
2021-05-14 12:44:23 +00:00
import { ShapeUtil, Bounds, Data, Shapes } from "types"
2021-05-10 12:16:57 +00:00
import BaseSession from "./base-session"
2021-05-14 21:05:21 +00:00
import shapes, { getShapeUtils } from "lib/shapes"
import { getBoundsFromPoints } from "utils/utils"
2021-05-10 12:16:57 +00:00
import * as vec from "utils/vec"
interface BrushSnapshot {
2021-05-12 11:27:33 +00:00
selectedIds: Set<string>
shapes: { id: string; test: (bounds: Bounds) => boolean }[]
2021-05-10 12:16:57 +00:00
}
export default class BrushSession extends BaseSession {
origin: number[]
snapshot: BrushSnapshot
constructor(data: Data, point: number[]) {
super(data)
this.origin = vec.round(point)
this.snapshot = BrushSession.getSnapshot(data)
}
update = (data: Data, point: number[]) => {
const { origin, snapshot } = this
const brushBounds = getBoundsFromPoints(origin, point)
2021-05-10 12:16:57 +00:00
2021-05-12 11:27:33 +00:00
for (let { test, id } of snapshot.shapes) {
if (test(brushBounds)) {
data.selectedIds.add(id)
} else if (data.selectedIds.has(id)) {
data.selectedIds.delete(id)
}
}
2021-05-10 12:16:57 +00:00
data.brush = brushBounds
2021-05-10 12:16:57 +00:00
}
cancel = (data: Data) => {
data.brush = undefined
2021-05-12 11:27:33 +00:00
data.selectedIds = new Set(this.snapshot.selectedIds)
2021-05-10 12:16:57 +00:00
}
complete = (data: Data) => {
data.brush = undefined
}
2021-05-12 11:27:33 +00:00
/**
* Get a snapshot of the current selected ids, for each shape that is
* not already selected, the shape's id and a test to see whether the
* brush will intersect that shape. For tests, start broad -> fine.
* @param data
* @returns
*/
static getSnapshot(data: Data): BrushSnapshot {
2021-05-10 12:16:57 +00:00
const {
selectedIds,
2021-05-10 12:16:57 +00:00
document: { pages },
currentPageId,
} = current(data)
return {
2021-05-12 11:27:33 +00:00
selectedIds: new Set(data.selectedIds),
shapes: Object.values(pages[currentPageId].shapes)
2021-05-12 11:27:33 +00:00
.filter((shape) => !selectedIds.has(shape.id))
2021-05-13 18:22:16 +00:00
.map((shape) => ({
id: shape.id,
test: (brushBounds: Bounds): boolean =>
2021-05-14 21:05:21 +00:00
getShapeUtils(shape).hitTestBounds(shape, brushBounds),
2021-05-13 18:22:16 +00:00
})),
2021-05-10 12:16:57 +00:00
}
}
}