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.

bounds-bg.tsx 2.3KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { useCallback, useRef } from 'react'
  2. import state, { useSelector } from 'state'
  3. import inputs from 'state/inputs'
  4. import styled from 'styles'
  5. import { deepCompareArrays, getPage } from 'utils/utils'
  6. function handlePointerDown(e: React.PointerEvent<SVGRectElement>) {
  7. if (!inputs.canAccept(e.pointerId)) return
  8. e.stopPropagation()
  9. e.currentTarget.setPointerCapture(e.pointerId)
  10. if (e.button === 0) {
  11. state.send('POINTED_BOUNDS', inputs.pointerDown(e, 'bounds'))
  12. } else if (e.button === 2) {
  13. state.send('RIGHT_POINTED', inputs.pointerDown(e, 'bounds'))
  14. }
  15. }
  16. function handlePointerUp(e: React.PointerEvent<SVGRectElement>) {
  17. if (!inputs.canAccept(e.pointerId)) return
  18. e.stopPropagation()
  19. e.currentTarget.releasePointerCapture(e.pointerId)
  20. state.send('STOPPED_POINTING', inputs.pointerUp(e))
  21. }
  22. export default function BoundsBg() {
  23. const rBounds = useRef<SVGRectElement>(null)
  24. const bounds = useSelector((state) => state.values.selectedBounds)
  25. const isSelecting = useSelector((s) => s.isIn('selecting'))
  26. const selectedIds = useSelector(
  27. (s) => Array.from(s.values.selectedIds.values()),
  28. deepCompareArrays
  29. )
  30. const rotation = useSelector((s) => {
  31. if (selectedIds.length === 1) {
  32. const { shapes } = getPage(s.data)
  33. const selected = Array.from(s.values.selectedIds.values())[0]
  34. return shapes[selected]?.rotation
  35. } else {
  36. return 0
  37. }
  38. })
  39. const isAllHandles = useSelector((s) => {
  40. const page = getPage(s.data)
  41. const selectedIds = Array.from(s.values.selectedIds.values())
  42. return (
  43. selectedIds.length === 1 &&
  44. page.shapes[selectedIds[0]]?.handles !== undefined
  45. )
  46. })
  47. if (isAllHandles) return null
  48. if (!bounds) return null
  49. if (!isSelecting) return null
  50. const { width, height } = bounds
  51. return (
  52. <StyledBoundsBg
  53. ref={rBounds}
  54. width={Math.max(1, width)}
  55. height={Math.max(1, height)}
  56. transform={`
  57. rotate(${rotation * (180 / Math.PI)},
  58. ${(bounds.minX + bounds.maxX) / 2},
  59. ${(bounds.minY + bounds.maxY) / 2})
  60. translate(${bounds.minX},${bounds.minY})
  61. rotate(${(bounds.rotation || 0) * (180 / Math.PI)}, 0, 0)`}
  62. onPointerDown={handlePointerDown}
  63. onPointerUp={handlePointerUp}
  64. pointerEvents="all"
  65. />
  66. )
  67. }
  68. const StyledBoundsBg = styled('rect', {
  69. fill: '$boundsBg',
  70. })