improve edges

This commit is contained in:
2026-03-07 10:10:13 +01:00
parent 5ccd369f1d
commit 7e42e74a1e
4 changed files with 128 additions and 37 deletions

View File

@@ -17,6 +17,7 @@ import ConfigNode from './components/graph/ConfigNode'
import FunctionNode from './components/graph/FunctionNode'
import RenderingNode from './components/graph/RenderingNode'
import VariableNode from './components/graph/VariableNode'
import { AnimatedEdge } from './components/graph/AnimatedEdge'
import FlowContext from './lib/flowContext'
import { useTheme } from './lib/themeContext'
import {
@@ -53,7 +54,9 @@ const initialNodes: Node[] = [
},
].map((n) => ({ ...n, id: n.id ?? genId() }))
const initialEdges: Edge[] = [{ id: 'e-config-render', source: 'config-1', target: 'render-1' }]
const initialEdges: Edge[] = [
{ id: 'e-config-render', source: 'config-1', target: 'render-1', type: 'animated' },
]
export default function App() {
const { theme, toggleTheme } = useTheme()
@@ -70,6 +73,8 @@ export default function App() {
[]
)
const edgeTypes = React.useMemo(() => ({ animated: AnimatedEdge }), [])
const onConnect = React.useCallback(
(params: Connection) => setEdges((eds) => addEdge(params, eds)),
[setEdges]
@@ -172,6 +177,8 @@ export default function App() {
onEdgesChange={onEdgesChange}
onConnect={onConnect}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
defaultEdgeOptions={{ type: 'animated' }}
colorMode={theme as ColorMode}
snapToGrid
snapGrid={SNAP_GRID}

View File

@@ -0,0 +1,99 @@
import React from 'react'
import {
BaseEdge,
getBezierPath,
type EdgeProps,
} from '@xyflow/react'
const EDGE_STROKE_WIDTH = 2
const DOT_MARKER_R = 1.5
export function AnimatedEdge({
id,
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
style,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
labelX,
labelY,
interactionWidth,
}: EdgeProps) {
const [edgePath] = getBezierPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
})
const startId = `animated-edge-dot-start-${id}`
const endId = `animated-edge-dot-end-${id}`
return (
<>
<defs>
<marker
id={startId}
markerWidth={DOT_MARKER_R * 2}
markerHeight={DOT_MARKER_R * 2}
refX={DOT_MARKER_R + 5}
refY={DOT_MARKER_R}
orient="auto"
>
<circle
r={DOT_MARKER_R}
cx={DOT_MARKER_R}
cy={DOT_MARKER_R}
className="fill-primary stroke-background"
strokeWidth={2}
/>
</marker>
<marker
id={endId}
markerWidth={DOT_MARKER_R * 2}
markerHeight={DOT_MARKER_R * 2}
refX={DOT_MARKER_R - 5}
refY={DOT_MARKER_R}
orient="auto"
>
<circle
r={DOT_MARKER_R}
cx={DOT_MARKER_R}
cy={DOT_MARKER_R}
className="fill-primary stroke-background"
strokeWidth={2}
/>
</marker>
</defs>
<BaseEdge
path={edgePath}
markerStart={`url(#${startId})`}
markerEnd={`url(#${endId})`}
style={{
strokeWidth: EDGE_STROKE_WIDTH,
...style,
}}
className="animated-edge-path"
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
labelX={labelX}
labelY={labelY}
interactionWidth={interactionWidth}
/>
</>
)
}

View File

@@ -32,6 +32,25 @@ body {
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.15);
}
/* Animated React Flow edges: thicker stroke + path animation */
.react-flow__edge path.animated-edge-path,
.animated-edge-path {
stroke-width: 4;
stroke: hsl(var(--foreground) / 0.6);
fill: none;
stroke-dasharray: 8 6;
animation: edge-flow 0.6s linear infinite;
}
@keyframes edge-flow {
from {
stroke-dashoffset: 0;
}
to {
stroke-dashoffset: 14;
}
}
/* Small helper for monospace pre output */
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, 'Roboto Mono', 'Courier New', monospace;