'use client' import { useMemo } from 'react' import { sankey as d3Sankey, sankeyLinkHorizontal, SankeyNode, SankeyLink, } from 'd3-sankey' import { FlowData } from '@/lib/types' import AnimatedPipe from './AnimatedPipe' import FlowParticles from './FlowParticles' import WaterDistortion from './WaterDistortion' interface SankeyDiagramProps { data: FlowData width?: number height?: number showLabels?: boolean speed?: 'slow' | 'normal' | 'fast' showParticles?: boolean showDistortion?: boolean maxParticles?: number className?: string } interface SNode { id: string label?: string color?: string } interface SLink { source: string target: string value: number color?: string } export default function SankeyDiagram({ data, width = 800, height = 400, showLabels = false, speed = 'normal', showParticles = true, showDistortion = false, maxParticles = 6, className = '', }: SankeyDiagramProps) { const { nodes, links } = useMemo(() => { const sankeyNodes = data.nodes.map(n => ({ ...n })) const sankeyLinks = data.links.map(l => ({ source: l.source, target: l.target, value: l.value, color: l.color, })) const generator = (d3Sankey as any)() .nodeId((d: any) => d.id) .nodeWidth(12) .nodePadding(16) .extent([[1, 1], [width - 1, height - 1]]) const result = generator({ nodes: sankeyNodes, links: sankeyLinks, }) return { nodes: result.nodes as any[], links: result.links as any[], } }, [data, width, height]) const linkPath = sankeyLinkHorizontal() const filterId = `distortion-${Math.random().toString(36).slice(2, 7)}` let particleCount = 0 return ( {showDistortion && } {/* Define paths for particles */} {links.map((link, i) => { const d = linkPath(link as any) return d ? ( ) : null })} {/* Links */} {links.map((link, i) => { const d = linkPath(link as any) if (!d) return null const linkWidth = Math.max(2, (link as any).width || 4) return ( ) })} {/* Particles */} {showParticles && links.map((link, i) => { if (particleCount >= maxParticles) return null const pCount = Math.min(2, maxParticles - particleCount) particleCount += pCount return ( ) })} {/* Nodes */} {nodes.map((node, i) => ( {showLabels && node.label && ( {node.label} )} ))} ) }