diff --git a/src/components/mindset/components/Scene/Board/Edges/index.tsx b/src/components/mindset/components/Scene/Board/Edges/index.tsx
index ab5e3f434..aedea3f1b 100644
--- a/src/components/mindset/components/Scene/Board/Edges/index.tsx
+++ b/src/components/mindset/components/Scene/Board/Edges/index.tsx
@@ -1,3 +1,4 @@
+import { Text } from '@react-three/drei'
import { useMemo } from 'react'
import { Vector3 } from 'three'
@@ -6,15 +7,22 @@ type Props = {
targetPosition: { x: number; y: number; z: number }
color?: string
arrowSize?: number
+ label?: string // Добавляем текстовую метку
}
-export const Edge = ({ sourcePosition, targetPosition, color = 'white', arrowSize = 1 }: Props) => {
- const points = useMemo(() => {
+export const Edge = ({ sourcePosition, targetPosition, color = 'white', arrowSize = 1, label = 'label' }: Props) => {
+ const { points, textPosition, textRotation } = useMemo(() => {
const start = new Vector3(sourcePosition.x, sourcePosition.y, sourcePosition.z)
const end = new Vector3(targetPosition.x, targetPosition.y, targetPosition.z)
+
+ // Вычисляем направление и середину линии
const direction = new Vector3().subVectors(end, start).normalize()
+ const midpoint = new Vector3().addVectors(start, end).multiplyScalar(0.5)
+
+ // Угол поворота текста относительно оси Z
+ const angle = Math.atan2(direction.y, direction.x)
- // Calculate arrowhead points
+ // Вычисляем точки для линии и стрелок
const arrowLeft = new Vector3()
.copy(direction)
.multiplyScalar(-arrowSize)
@@ -25,21 +33,36 @@ export const Edge = ({ sourcePosition, targetPosition, color = 'white', arrowSiz
.multiplyScalar(-arrowSize)
.applyAxisAngle(new Vector3(0, 0, 1), -Math.PI / 6)
- // Return line points + arrowhead points
- return [start, end, end.clone(), end.clone().add(arrowLeft), end.clone(), end.clone().add(arrowRight)]
+ const pointsFinal = [start, end, end.clone(), end.clone().add(arrowLeft), end.clone(), end.clone().add(arrowRight)]
+
+ return { points: pointsFinal, textPosition: midpoint, textRotation: angle }
}, [sourcePosition, targetPosition, arrowSize])
return (
-
-
- [p.x, p.y, p.z]))}
- attach="attributes-position"
- count={points.length}
- itemSize={3}
- />
-
-
-
+ <>
+
+
+ [p.x, p.y, p.z]))}
+ attach="attributes-position"
+ count={points.length}
+ itemSize={3}
+ />
+
+
+
+ {label && (
+
+ {label}
+
+ )}
+ >
)
}
diff --git a/src/components/mindset/components/Scene/Board/index.tsx b/src/components/mindset/components/Scene/Board/index.tsx
index 7dbe0e359..7794968c7 100644
--- a/src/components/mindset/components/Scene/Board/index.tsx
+++ b/src/components/mindset/components/Scene/Board/index.tsx
@@ -1,12 +1,27 @@
import { useThree } from '@react-three/fiber'
import { Fragment, useEffect, useMemo, useState } from 'react'
+import { Vector3 } from 'three'
import { useDataStore } from '~/stores/useDataStore'
+import { Link } from '~/types'
import { Edge } from './Edges'
import { Node } from './Node'
const nodeWidth = 144 / 10
const nodeHeight = 84 / 10
+type LinkExtended = Link & {
+ sourcePositions: {
+ x?: number
+ y?: number
+ z?: number
+ }
+ targetPositions: {
+ x?: number
+ y?: number
+ z?: number
+ }
+}
+
export const Board = () => {
const state = useThree()
const { dataInitial } = useDataStore((s) => s)
@@ -69,68 +84,63 @@ export const Board = () => {
})
.filter((node) => node.node_type !== 'Clip' && node.node_type !== 'Episode' && node.node_type !== 'Show')
- // 'fc9fc515-d9f8-4e28-ac4a-89597db29a2f'
- // '2f919e76-90cd-41e2-92eb-15d8c89e1fd2'
- // Step 2: Calculate positions for related nodes
- const relatedNodes = nodesWithPositions.reduce((acc, marker) => {
- const related = dataInitial.nodes
- .filter((node) =>
- dataInitial.links.some(
- (edge) =>
- node.node_type !== 'Episode' &&
- node.node_type !== 'Clip' &&
- ((edge.source === marker.ref_id && edge.target === node.ref_id) ||
- (edge.target === marker.ref_id && edge.source === node.ref_id)),
- ),
- )
- .map((relatedNode, index) => {
- // Calculate positions relative to the main node
- const { x } = marker
- const y = (Math.floor(index / 2) + 1) * nodeHeight * 2 * (index % 2 === 0 ? 1 : -1) // Offset based on index
- const z = 0
-
- return { ...relatedNode, x, y, z }
- })
-
- acc[marker.ref_id] = related
+ // Step 2 & Step 3: Calculate positions for related nodes and edges
+ const relatedNodesWithEdges = nodesWithPositions.reduce((acc, marker) => {
+ const linksRelatedToNodeWithoutTimestamp = dataInitial.links.filter(
+ (link) => !link?.properties?.start && [link.target, link.source].includes(marker.ref_id),
+ )
- return acc
- }, {} as Record)
-
- // Step 3: Calculate edge positions based on node and related node positions
- // eslint-disable-next-line camelcase
- const edgesWithPositions = Object.entries(relatedNodes).flatMap(([ref_id, related]) => {
- // Gather all node ids in this group (ref_id + related nodes)
- // eslint-disable-next-line camelcase
- const allNodesInGroup = [ref_id, ...related.map((node) => node.ref_id)]
-
- // Filter edges that connect nodes within this group
- const edgesInGroup = dataInitial.links.filter(
- (edge) => allNodesInGroup.includes(edge.source) && allNodesInGroup.includes(edge.target),
+ const relatedNodes = dataInitial.nodes.filter(
+ (node) =>
+ node.node_type !== 'Episode' &&
+ node.node_type !== 'Clip' &&
+ node.ref_id !== marker.ref_id &&
+ linksRelatedToNodeWithoutTimestamp.some((link) => [link.source, link.target].includes(node.ref_id)),
)
- // Map these edges to include source and target positions
- return edgesInGroup.map((edge) => {
- const sourceNode =
- nodesWithPositions.find((node) => node.ref_id === edge.source) ||
- related.find((node) => node.ref_id === edge.source)
+ const relatedNodesWithPositions = relatedNodes.map((relatedNode, index) => {
+ const { x } = marker
+ const y = (Math.floor(index / 2) + 1) * nodeHeight * 2 * (index % 2 === 0 ? 1 : -1) // Offset based on index
+ const z = 0
+
+ return { ...relatedNode, x, y, z }
+ })
+
+ const relatedLinksWithPositions = linksRelatedToNodeWithoutTimestamp.map((link) => {
+ if (link.source === marker.ref_id) {
+ const targetNode = relatedNodesWithPositions.find((node) => node.ref_id === link.target)
+
+ return {
+ ...link,
+ sourcePositions: { x: marker.x, y: marker.y, z: marker.z },
+ targetPositions: { x: targetNode?.x, y: targetNode?.y, z: targetNode?.z },
+ }
+ }
- const targetNode =
- nodesWithPositions.find((node) => node.ref_id === edge.target) ||
- related.find((node) => node.ref_id === edge.target)
+ const sourceNode = relatedNodesWithPositions.find((node) => node.ref_id === link.source)
return {
- ...edge,
- sourcePosition: sourceNode ? { x: sourceNode.x, y: sourceNode.y, z: sourceNode.z } : null,
- targetPosition: targetNode ? { x: targetNode.x, y: targetNode.y, z: targetNode.z } : null,
+ ...link,
+ sourcePositions: { x: sourceNode?.x, y: sourceNode?.y, z: sourceNode?.z },
+ targetPositions: { x: marker.x, y: marker.y, z: marker.z },
}
})
- })
+
+ acc[marker.ref_id] = {
+ nodes: relatedNodesWithPositions,
+ edges: relatedLinksWithPositions,
+ }
+
+ return acc
+ }, {} as Record)
+
+ // Combine all edges from relatedNodesWithEdges
+ const allEdgesWithPositions = Object.values(relatedNodesWithEdges).flatMap((group) => group.edges)
return {
nodes: nodesWithPositions,
- edges: edgesWithPositions,
- relatedNodes,
+ edges: allEdgesWithPositions,
+ relatedNodes: Object.fromEntries(Object.entries(relatedNodesWithEdges).map(([key, group]) => [key, group.nodes])),
}
}, [dataInitial, viewport.width])
@@ -170,21 +180,17 @@ export const Board = () => {
))}
{/* Render Edges */}
- {processedData.edges.map((edge, index) => {
- if (!edge.sourcePosition || !edge.targetPosition) {
- return null
- }
-
- const { sourcePosition, targetPosition } = edge
-
- return (
- // eslint-disable-next-line react/no-array-index-key
-
- {/* Line */}
-
-
- )
- })}
+ {processedData.edges.map((edge, index) =>
+ edge?.sourcePositions && edge?.targetPositions ? (
+
+ ) : null,
+ )}
>
)
}