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.

brush-session.ts 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { current } from "immer"
  2. import { ShapeUtil, Bounds, Data, Shapes } from "types"
  3. import BaseSession from "./base-session"
  4. import shapes, { getShapeUtils } from "lib/shape-utils"
  5. import { getBoundsFromPoints } from "utils/utils"
  6. import * as vec from "utils/vec"
  7. interface BrushSnapshot {
  8. selectedIds: Set<string>
  9. shapes: { id: string; test: (bounds: Bounds) => boolean }[]
  10. }
  11. export default class BrushSession extends BaseSession {
  12. origin: number[]
  13. snapshot: BrushSnapshot
  14. constructor(data: Data, point: number[]) {
  15. super(data)
  16. this.origin = vec.round(point)
  17. this.snapshot = BrushSession.getSnapshot(data)
  18. }
  19. update = (data: Data, point: number[]) => {
  20. const { origin, snapshot } = this
  21. const brushBounds = getBoundsFromPoints([origin, point])
  22. for (let { test, id } of snapshot.shapes) {
  23. if (test(brushBounds)) {
  24. data.selectedIds.add(id)
  25. } else if (data.selectedIds.has(id)) {
  26. data.selectedIds.delete(id)
  27. }
  28. }
  29. data.brush = brushBounds
  30. }
  31. cancel = (data: Data) => {
  32. data.brush = undefined
  33. data.selectedIds = new Set(this.snapshot.selectedIds)
  34. }
  35. complete = (data: Data) => {
  36. data.brush = undefined
  37. }
  38. /**
  39. * Get a snapshot of the current selected ids, for each shape that is
  40. * not already selected, the shape's id and a test to see whether the
  41. * brush will intersect that shape. For tests, start broad -> fine.
  42. * @param data
  43. * @returns
  44. */
  45. static getSnapshot(data: Data): BrushSnapshot {
  46. const {
  47. selectedIds,
  48. document: { pages },
  49. currentPageId,
  50. } = current(data)
  51. return {
  52. selectedIds: new Set(data.selectedIds),
  53. shapes: Object.values(pages[currentPageId].shapes)
  54. .filter((shape) => !selectedIds.has(shape.id))
  55. .map((shape) => ({
  56. id: shape.id,
  57. test: (brushBounds: Bounds): boolean =>
  58. getShapeUtils(shape).hitTestBounds(shape, brushBounds),
  59. })),
  60. }
  61. }
  62. }