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.

page.tsx 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import { getShapeUtils } from 'lib/shape-utils'
  2. import state, { useSelector } from 'state'
  3. import { Bounds, GroupShape, PageState } from 'types'
  4. import { boundsCollide, boundsContain } from 'utils/bounds'
  5. import { deepCompareArrays, getPage, screenToWorld } from 'utils/utils'
  6. import Shape from './shape'
  7. /*
  8. On each state change, compare node ids of all shapes
  9. on the current page. Kind of expensive but only happens
  10. here; and still cheaper than any other pattern I've found.
  11. */
  12. const noOffset = [0, 0]
  13. const viewportCache = new WeakMap<PageState, Bounds>()
  14. export default function Page() {
  15. const currentPageShapeIds = useSelector((s) => {
  16. const page = getPage(s.data)
  17. const pageState = s.data.pageStates[page.id]
  18. if (!viewportCache.has(pageState)) {
  19. const [minX, minY] = screenToWorld([0, 0], s.data)
  20. const [maxX, maxY] = screenToWorld(
  21. [window.innerWidth, window.innerHeight],
  22. s.data
  23. )
  24. viewportCache.set(pageState, {
  25. minX,
  26. minY,
  27. maxX,
  28. maxY,
  29. height: maxX - minX,
  30. width: maxY - minY,
  31. })
  32. }
  33. const viewport = viewportCache.get(pageState)
  34. return Object.values(page.shapes)
  35. .filter((shape) => shape.parentId === page.id)
  36. .filter((shape) => {
  37. const shapeBounds = getShapeUtils(shape).getBounds(shape)
  38. return (
  39. boundsContain(viewport, shapeBounds) ||
  40. boundsCollide(viewport, shapeBounds)
  41. )
  42. })
  43. .sort((a, b) => a.childIndex - b.childIndex)
  44. .map((shape) => shape.id)
  45. }, deepCompareArrays)
  46. const isSelecting = useSelector((s) => s.isIn('selecting'))
  47. return (
  48. <g pointerEvents={isSelecting ? 'all' : 'none'}>
  49. {currentPageShapeIds.map((shapeId) => (
  50. <Shape
  51. key={shapeId}
  52. id={shapeId}
  53. isSelecting={isSelecting}
  54. parentPoint={noOffset}
  55. />
  56. ))}
  57. </g>
  58. )
  59. }