Skip to content

Commit

Permalink
Merge pull request #2580 from stakwork/feature/selection-v2
Browse files Browse the repository at this point in the history
Feature/selection v2
  • Loading branch information
Rassl authored Dec 25, 2024
2 parents 10ec55a + bd90e83 commit 88681b5
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 266 deletions.
14 changes: 4 additions & 10 deletions src/components/Universe/Controls/CameraAnimations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ export const useCameraAnimations = (

useAutoNavigate(cameraControlsRef)

const isUserDragging = useControlStore((s) => s.isUserDragging)

const { graphRadius, disableCameraRotation } = useGraphStore((s) => s)
const { graphRadius } = useGraphStore((s) => s)

useEffect(() => {
if (!enabled) {
Expand All @@ -33,13 +31,6 @@ export const useCameraAnimations = (
}
}, [enabled])

// useEffect(() => {
// if (cameraControlsRef.current && graphRadius) {
// cameraControlsRef.current.maxDistance = cameraControlsRef.current.getDistanceToFitSphere(graphRadius + 200)
// cameraControlsRef.current.minDistance = 100
// }
// }, [graphRadius, cameraControlsRef])

useEffect(() => {
if (!selectedNode && cameraControlsRef.current) {
cameraControlsRef.current.setLookAt(
Expand All @@ -58,6 +49,9 @@ export const useCameraAnimations = (
useFrame((_, delta) => {
if (cameraControlsRef.current) {
// do camera rotation
const { disableCameraRotation } = useGraphStore.getState()
const { isUserDragging } = useControlStore.getState()

if (!disableCameraRotation && !isUserDragging) {
cameraControlsRef.current.azimuthAngle += autoRotateSpeed * delta * MathUtils.DEG2RAD
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ const _Connection = (props: LineComponentProps) => {
points={[sourceX, sourceY, sourceZ, targetX, targetY, targetZ]}
/>
<mesh>
<planeGeometry args={[label.length * 6, 12]} />
<planeGeometry args={[label.length * 2, 2]} />
<meshBasicMaterial color="black" />
<Text anchorX="center" anchorY="middle" color="white" {...fontProps} fontSize={6}>
<Text anchorX="center" anchorY="middle" color="white" {...fontProps} fontSize={2}>
{label}
</Text>
</mesh>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,97 @@
import { memo } from 'react'
import { memo, useEffect, useRef } from 'react'
import { Box3, Color, Group, Sphere, Vector3 } from 'three'
import { Line2 } from 'three-stdlib'
import { useShallow } from 'zustand/react/shallow'
import { useGraphStore } from '~/stores/useGraphStore'
import { Link } from '~/types'
import { Link, NodeExtended } from '~/types'
import { LinkPosition } from '../../..'
import { Connection } from './Connection'

type Props = {
linksPosition: Map<string, LinkPosition>
links: Link[]
nodes: NodeExtended[]
}

export const Connections = memo(({ linksPosition }: Props) => {
const { selectionGraphData } = useGraphStore((s) => s)
export const Connections = memo(({ links, nodes }: Props) => {
const groupRef = useRef<Group>(null)
const linksPositionRef = useRef(new Map<string, LinkPosition>())
const { setSelectionGraphRadius } = useGraphStore(useShallow((s) => s))

useEffect(() => {
if (!groupRef.current) {
return
}

console.log('connection to updated')

const grConnections = groupRef.current

grConnections.children.forEach((g, i) => {
const r = g.children[0]
const text = g.children[1]

if (r instanceof Line2) {
const Line = r as Line2
const link = links[i]

if (link) {
const sourceNode = nodes.find((n: NodeExtended) => n.ref_id === link.source)
const targetNode = nodes.find((n: NodeExtended) => n.ref_id === link.target)

if (!sourceNode || !targetNode) {
return
}

const { x: sx, y: sy } = sourceNode
const { x: tx, y: ty } = targetNode

linksPositionRef.current.set(link.ref_id, {
sx,
sy,
tx,
ty,
sz: 0,
tz: 0,
})

const midPoint = new Vector3((sx + tx) / 2, (sy + ty) / 2, 0)

text.position.set(midPoint.x, midPoint.y, 1)

let angle = Math.atan2(ty - sy, tx - sx)

if (tx < sx || (Math.abs(tx - sx) < 0.01 && ty < sy)) {
angle += Math.PI
}

text.rotation.set(0, 0, angle)

Line.geometry.setPositions([sx, sy, 0, tx, ty, 0])

const { material } = Line

material.color = new Color('white')
}
}
})

console.log('connection updated')

const nodesVector = nodes.map((i: NodeExtended) => new Vector3(i.x, i.y, i.z))

const boundingBox = new Box3().setFromPoints(nodesVector)

const boundingSphere = new Sphere()

boundingBox.getBoundingSphere(boundingSphere)

setSelectionGraphRadius(boundingSphere.radius)
}, [links, setSelectionGraphRadius, nodes])

return (
<group name="simulation-3d-group__connections">
{selectionGraphData?.links.map((l: Link) => {
const position = linksPosition.get(l.ref_id) || {
<group ref={groupRef} name="simulation-3d-group__connections">
{links?.map((l: Link) => {
const position = linksPositionRef.current?.get(l.ref_id) || {
sx: 0,
sy: 0,
sz: 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Html } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'
import styled from 'styled-components'
import { Mesh, Vector3 } from 'three'
import { Flex } from '~/components/common/Flex'
import { Icons } from '~/components/Icons'
import CloseIcon from '~/components/Icons/CloseIcon'
Expand All @@ -17,12 +21,25 @@ type Props = {
node: NodeExtended
rounded?: boolean
selected: boolean
onClick: () => void
onClick: (id: string) => void
x: number
y: number
z: number
id: string
}

export const Node = ({ onClick, node, selected, rounded = true }: Props) => {
export const Node = ({ onClick, node, selected, rounded = true, x, y, z, id }: Props) => {
const nodeRef = useRef<Mesh | null>(null)

const { normalizedSchemasByType, getNodeKeysByType } = useSchemaStore((s) => s)
const setSelectedNode = useGraphStore((s) => s.setSelectedNode)
const targetPosition = new Vector3(x, y, z)

useFrame(() => {
if (nodeRef.current) {
nodeRef.current.position.lerp(targetPosition, 0.05)
}
})

const primaryIcon = normalizedSchemasByType[node.node_type]?.icon

Expand All @@ -34,26 +51,32 @@ export const Node = ({ onClick, node, selected, rounded = true }: Props) => {
const titleShortened = title ? truncateText(title, 30) : ''

return (
<Wrapper align="center" direction="row" justify="flex-start">
<>
{selected ? (
<Selected rounded={false}>
<IconButton onClick={() => setSelectedNode(null)}>
<CloseIcon />
</IconButton>
<div>{Icon ? <Icon /> : <NodesIcon />}</div>
<Text>{titleShortened}</Text>
</Selected>
) : (
<mesh ref={nodeRef}>
<Html center sprite zIndexRange={[0, 0]}>
<Wrapper align="center" direction="row" justify="flex-start">
<>
<Tag onClick={onClick} rounded={rounded}>
<div>{Icon ? <Icon /> : <NodesIcon />}</div>
</Tag>
<Text>{titleShortened}</Text>
{selected ? (
<Selected rounded={false}>
<IconButton onClick={() => setSelectedNode(null)}>
<CloseIcon />
</IconButton>
<div>{Icon ? <Icon /> : <NodesIcon />}</div>
<Text>{titleShortened}</Text>
</Selected>
) : (
<>
<Tag onClick={() => onClick(id)} rounded={rounded}>
<Avatar align="center" justify="center" src={node?.properties?.image_url || ''}>
{!node?.properties?.image_url ? <span>{Icon ? <Icon /> : <NodesIcon />}</span> : null}
</Avatar>
</Tag>
<Text>{titleShortened}</Text>
</>
)}
</>
)}
</>
</Wrapper>
</Wrapper>
</Html>
</mesh>
)
}

Expand Down Expand Up @@ -105,8 +128,8 @@ const IconButton = styled(Flex)`
position: absolute;
top: -10px;
right: -10px;
width: 24px;
height: 24px;
width: 30px;
height: 30px;
border-radius: 40px;
display: flex;
Expand All @@ -115,8 +138,22 @@ const IconButton = styled(Flex)`
background: black;
color: #ffffff;
border-radius: 100%;
font-size: 16px;
font-size: 30px;
cursor: pointer;
transition: opacity 0.4s;
box-shadow: 0px 2px 12px rgba(0, 0, 0, 0.5);
`

type AvatarProps = {
src: string
}

const Avatar = styled(Flex)<AvatarProps>`
background-image: ${({ src }) => `url(${src})`};
background-size: cover;
background-position: center;
background-repeat: no-repeat;
width: 32px;
height: 32px;
border-radius: 50%;
`
Loading

0 comments on commit 88681b5

Please sign in to comment.