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

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