| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- import { Bounds, Data, ShapeType } from 'types'
- import BaseSession from './base-session'
- import { getShapeUtils } from 'state/shape-utils'
- import { deepClone, getBoundsFromPoints, setToArray } from 'utils'
- import vec from 'utils/vec'
- import tld from 'utils/tld'
-
- export default class BrushSession extends BaseSession {
- origin: number[]
- snapshot: BrushSnapshot
-
- constructor(data: Data, point: number[]) {
- super(data)
-
- this.origin = vec.round(point)
-
- this.snapshot = getBrushSnapshot(data)
- }
-
- update = (data: Data, point: number[]): void => {
- const { origin, snapshot } = this
-
- const brushBounds = getBoundsFromPoints([origin, point])
-
- const hits = new Set<string>([])
-
- const selectedIds = new Set(snapshot.selectedIds)
-
- for (const id in snapshot.shapeHitTests) {
- if (selectedIds.has(id)) continue
-
- const { test, selectId } = snapshot.shapeHitTests[id]
- if (!hits.has(selectId)) {
- if (test(brushBounds)) {
- hits.add(selectId)
-
- // When brushing a shape, select its top group parent.
- if (!selectedIds.has(selectId)) {
- selectedIds.add(selectId)
- }
- } else if (selectedIds.has(selectId)) {
- selectedIds.delete(selectId)
- }
- }
- }
-
- tld.getPageState(data).selectedIds = selectedIds
-
- data.brush = brushBounds
- }
-
- cancel = (data: Data): void => {
- data.brush = undefined
- tld.setSelectedIds(data, this.snapshot.selectedIds)
- }
-
- complete = (data: Data): void => {
- data.brush = undefined
- }
- }
-
- /**
- * 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.
- */
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
- export function getBrushSnapshot(data: Data) {
- const cData = data
- const { selectedIds } = tld.getPageState(cData)
-
- const shapesToTest = tld
- .getShapes(cData)
- .filter((shape) => shape.type !== ShapeType.Group && !shape.isHidden)
- .filter(
- (shape) => !(selectedIds.has(shape.id) || selectedIds.has(shape.parentId))
- )
- .map(deepClone)
-
- return {
- selectedIds: setToArray(selectedIds),
- shapeHitTests: Object.fromEntries(
- shapesToTest.map((shape) => {
- return [
- shape.id,
- {
- selectId: tld.getTopParentId(data, shape.id),
- test: (bounds: Bounds) => {
- return getShapeUtils(shape).hitTestBounds(shape, bounds)
- },
- },
- ]
- })
- ),
- }
- }
-
- export type BrushSnapshot = ReturnType<typeof getBrushSnapshot>
|