Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

bounding-box.tsx 2.6KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import * as React from 'react'
  2. import { Edge, Corner } from 'types'
  3. import { useSelector } from 'state'
  4. import {
  5. deepCompareArrays,
  6. getBoundsCenter,
  7. getCurrentCamera,
  8. getPage,
  9. getSelectedShapes,
  10. isMobile,
  11. } from 'utils/utils'
  12. import CenterHandle from './center-handle'
  13. import CornerHandle from './corner-handle'
  14. import EdgeHandle from './edge-handle'
  15. import RotateHandle from './rotate-handle'
  16. import Handles from './handles'
  17. export default function Bounds() {
  18. const isBrushing = useSelector((s) => s.isIn('brushSelecting'))
  19. const isSelecting = useSelector((s) => s.isIn('selecting'))
  20. const zoom = useSelector((s) => getCurrentCamera(s.data).zoom)
  21. const bounds = useSelector((s) => s.values.selectedBounds)
  22. const selectedIds = useSelector(
  23. (s) => Array.from(s.values.selectedIds.values()),
  24. deepCompareArrays
  25. )
  26. const rotation = useSelector(({ data }) =>
  27. data.selectedIds.size === 1 ? getSelectedShapes(data)[0].rotation : 0
  28. )
  29. const isAllLocked = useSelector((s) => {
  30. const page = getPage(s.data)
  31. return selectedIds.every((id) => page.shapes[id]?.isLocked)
  32. })
  33. const isSingleHandles = useSelector((s) => {
  34. const page = getPage(s.data)
  35. return (
  36. selectedIds.length === 1 &&
  37. page.shapes[selectedIds[0]]?.handles !== undefined
  38. )
  39. })
  40. if (!bounds) return null
  41. if (!isSelecting) return null
  42. if (isSingleHandles) return null
  43. const size = (isMobile().any ? 10 : 8) / zoom // Touch target size
  44. return (
  45. <g
  46. pointerEvents={isBrushing ? 'none' : 'all'}
  47. transform={`
  48. rotate(${rotation * (180 / Math.PI)},
  49. ${(bounds.minX + bounds.maxX) / 2},
  50. ${(bounds.minY + bounds.maxY) / 2})
  51. translate(${bounds.minX},${bounds.minY})
  52. rotate(${(bounds.rotation || 0) * (180 / Math.PI)}, 0, 0)`}
  53. >
  54. <CenterHandle bounds={bounds} isLocked={isAllLocked} />
  55. {!isAllLocked && (
  56. <>
  57. <EdgeHandle size={size} bounds={bounds} edge={Edge.Top} />
  58. <EdgeHandle size={size} bounds={bounds} edge={Edge.Right} />
  59. <EdgeHandle size={size} bounds={bounds} edge={Edge.Bottom} />
  60. <EdgeHandle size={size} bounds={bounds} edge={Edge.Left} />
  61. <CornerHandle size={size} bounds={bounds} corner={Corner.TopLeft} />
  62. <CornerHandle size={size} bounds={bounds} corner={Corner.TopRight} />
  63. <CornerHandle
  64. size={size}
  65. bounds={bounds}
  66. corner={Corner.BottomRight}
  67. />
  68. <CornerHandle
  69. size={size}
  70. bounds={bounds}
  71. corner={Corner.BottomLeft}
  72. />
  73. <RotateHandle size={size} bounds={bounds} />
  74. </>
  75. )}
  76. </g>
  77. )
  78. }