您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

page.tsx 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { useSelector } from 'state'
  2. import tld from 'utils/tld'
  3. import { Data, Shape, ShapeType } from 'types'
  4. import { getShapeUtils } from 'state/shape-utils'
  5. import { boundsCollide, boundsContain } from 'utils'
  6. import ShapeComponent from './shape'
  7. /*
  8. On each state change, populate a tree structure with all of
  9. the shapes that we need to render..
  10. */
  11. interface Node {
  12. shape: Shape
  13. children: Node[]
  14. isEditing: boolean
  15. isHovered: boolean
  16. isSelected: boolean
  17. isDarkMode: boolean
  18. isCurrentParent: boolean
  19. }
  20. export default function Page(): JSX.Element {
  21. // Get a tree of shapes to render
  22. const shapeTree = useSelector((s) => {
  23. // Get the shapes that fit into the current viewport
  24. const viewport = tld.getViewport(s.data)
  25. const shapesToShow = s.values.currentShapes.filter((shape) => {
  26. const shapeBounds = getShapeUtils(shape).getBounds(shape)
  27. return (
  28. shape.type === ShapeType.Ray ||
  29. shape.type === ShapeType.Line ||
  30. boundsContain(viewport, shapeBounds) ||
  31. boundsCollide(viewport, shapeBounds)
  32. )
  33. })
  34. // Should we allow shapes to be hovered?
  35. const allowHovers = s.isInAny('selecting', 'text', 'editingShape')
  36. // Populate the shape tree
  37. const tree: Node[] = []
  38. shapesToShow.forEach((shape) =>
  39. addToTree(s.data, s.values.selectedIds, allowHovers, tree, shape)
  40. )
  41. return tree
  42. })
  43. return (
  44. <>
  45. {shapeTree.map((node) => (
  46. <ShapeNode key={node.shape.id} node={node} />
  47. ))}
  48. </>
  49. )
  50. }
  51. interface ShapeNodeProps {
  52. node: Node
  53. parentPoint?: number[]
  54. }
  55. const ShapeNode = ({
  56. node: {
  57. shape,
  58. children,
  59. isEditing,
  60. isHovered,
  61. isDarkMode,
  62. isSelected,
  63. isCurrentParent,
  64. },
  65. }: ShapeNodeProps) => {
  66. return (
  67. <>
  68. <ShapeComponent
  69. shape={shape}
  70. isEditing={isEditing}
  71. isHovered={isHovered}
  72. isSelected={isSelected}
  73. isDarkMode={isDarkMode}
  74. isCurrentParent={isCurrentParent}
  75. />
  76. {children.map((childNode) => (
  77. <ShapeNode key={childNode.shape.id} node={childNode} />
  78. ))}
  79. </>
  80. )
  81. }
  82. /**
  83. * Populate the shape tree. This helper is recursive and only one call is needed.
  84. *
  85. * ### Example
  86. *
  87. *```ts
  88. * addDataToTree(data, selectedIds, allowHovers, branch, shape)
  89. *```
  90. */
  91. function addToTree(
  92. data: Data,
  93. selectedIds: string[],
  94. allowHovers: boolean,
  95. branch: Node[],
  96. shape: Shape
  97. ): void {
  98. const node = {
  99. shape,
  100. children: [],
  101. isHovered: data.hoveredId === shape.id,
  102. isCurrentParent: data.currentParentId === shape.id,
  103. isEditing: data.editingId === shape.id,
  104. isDarkMode: data.settings.isDarkMode,
  105. isSelected: selectedIds.includes(shape.id),
  106. }
  107. branch.push(node)
  108. if (shape.children) {
  109. shape.children
  110. .map((id) => tld.getShape(data, id))
  111. .sort((a, b) => a.childIndex - b.childIndex)
  112. .forEach((childShape) => {
  113. addToTree(data, selectedIds, allowHovers, node.children, childShape)
  114. })
  115. }
  116. }