2021-06-03 21:40:27 +00:00
|
|
|
import { current } from 'immer'
|
|
|
|
import { Bounds, Data } from 'types'
|
|
|
|
import BaseSession from './base-session'
|
|
|
|
import { getShapeUtils } from 'lib/shape-utils'
|
|
|
|
import { getBoundsFromPoints, getShapes } from 'utils/utils'
|
|
|
|
import * as vec from 'utils/vec'
|
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)
|
|
|
|
|
2021-05-22 15:45:24 +00:00
|
|
|
this.snapshot = getBrushSnapshot(data)
|
2021-05-10 12:16:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
update = (data: Data, point: number[]) => {
|
|
|
|
const { origin, snapshot } = this
|
|
|
|
|
2021-05-18 08:32:20 +00:00
|
|
|
const brushBounds = getBoundsFromPoints([origin, point])
|
2021-05-10 12:16:57 +00:00
|
|
|
|
2021-05-22 15:45:24 +00:00
|
|
|
for (let id in snapshot.shapeHitTests) {
|
|
|
|
const test = snapshot.shapeHitTests[id]
|
2021-05-12 11:27:33 +00:00
|
|
|
if (test(brushBounds)) {
|
2021-06-03 21:40:27 +00:00
|
|
|
if (!data.selectedIds.has(id)) {
|
|
|
|
data.selectedIds.add(id)
|
|
|
|
}
|
2021-05-12 11:27:33 +00:00
|
|
|
} else if (data.selectedIds.has(id)) {
|
|
|
|
data.selectedIds.delete(id)
|
|
|
|
}
|
|
|
|
}
|
2021-05-10 12:16:57 +00:00
|
|
|
|
2021-05-11 10:13:07 +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-22 15:45:24 +00:00
|
|
|
}
|
2021-05-10 12:16:57 +00:00
|
|
|
|
2021-05-22 15:45:24 +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.
|
|
|
|
*/
|
|
|
|
export function getBrushSnapshot(data: Data) {
|
|
|
|
return {
|
|
|
|
selectedIds: new Set(data.selectedIds),
|
|
|
|
shapeHitTests: Object.fromEntries(
|
|
|
|
getShapes(current(data)).map((shape) => [
|
|
|
|
shape.id,
|
|
|
|
(bounds: Bounds) => getShapeUtils(shape).hitTestBounds(shape, bounds),
|
|
|
|
])
|
|
|
|
),
|
2021-05-10 12:16:57 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-22 15:45:24 +00:00
|
|
|
|
|
|
|
export type BrushSnapshot = ReturnType<typeof getBrushSnapshot>
|