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.

usePageShapes.ts 1.3KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. import { useEffect } from 'react'
  2. import state, { useSelector } from 'state'
  3. import { getShapeUtils } from 'state/shape-utils'
  4. import { PageState, Bounds } from 'types'
  5. import {
  6. boundsCollide,
  7. boundsContain,
  8. debounce,
  9. deepCompareArrays,
  10. } from 'utils'
  11. import tld from 'utils/tld'
  12. const viewportCache = new WeakMap<PageState, Bounds>()
  13. export default function usePageShapes(): string[] {
  14. // Reset the viewport cache when the window resizes
  15. useEffect(() => {
  16. const handleResize = debounce(() => state.send('RESIZED_WINDOW'), 32)
  17. window.addEventListener('resize', handleResize)
  18. return () => {
  19. window.removeEventListener('resize', handleResize)
  20. }
  21. }, [])
  22. // Get the shapes that fit into the current window
  23. const visiblePageShapeIds = useSelector((s) => {
  24. const pageState = tld.getPageState(s.data)
  25. if (!viewportCache.has(pageState)) {
  26. const viewport = tld.getViewport(s.data)
  27. viewportCache.set(pageState, viewport)
  28. }
  29. const viewport = viewportCache.get(pageState)
  30. return s.values.currentShapes
  31. .filter((shape) => {
  32. const shapeBounds = getShapeUtils(shape).getBounds(shape)
  33. return (
  34. boundsContain(viewport, shapeBounds) ||
  35. boundsCollide(viewport, shapeBounds)
  36. )
  37. })
  38. .map((shape) => shape.id)
  39. }, deepCompareArrays)
  40. return visiblePageShapeIds
  41. }