()
| 35 | } |
| 36 | |
| 37 | export default function App() { |
| 38 | const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); |
| 39 | const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); |
| 40 | |
| 41 | const onConnect = (params: Connection) => { |
| 42 | connect(params.source, params.target); |
| 43 | setEdges((eds) => addEdge(params, eds)) |
| 44 | } |
| 45 | |
| 46 | function addOscNode() { |
| 47 | const id = Math.random().toString().slice(2, 8); |
| 48 | const position = { x: 0, y: 0 }; |
| 49 | const type = 'osc'; |
| 50 | const data = {frequency: 400, type: 'sine' }; |
| 51 | |
| 52 | setNodes([...nodes, {id, type, data, position}]) |
| 53 | createAudioNode(id, type, data); |
| 54 | } |
| 55 | |
| 56 | function addVolumeNode() { |
| 57 | const id = Math.random().toString().slice(2, 8); |
| 58 | const data = { gain: 0.5 }; |
| 59 | const position = { x: 0, y: 0 }; |
| 60 | const type = 'volume'; |
| 61 | |
| 62 | setNodes([...nodes, {id, type, data, position}]) |
| 63 | createAudioNode(id, type, data); |
| 64 | } |
| 65 | |
| 66 | return ( |
| 67 | <div style={{ width: '100vw', height: '100vh'}}> |
| 68 | <ReactFlow |
| 69 | nodes={nodes} |
| 70 | edges={edges} |
| 71 | onNodesChange={onNodesChange} |
| 72 | onEdgesChange={onEdgesChange} |
| 73 | onConnect={onConnect} |
| 74 | nodeTypes={nodeTypes} |
| 75 | fitView |
| 76 | > |
| 77 | <Controls/> |
| 78 | <MiniMap/> |
| 79 | <Background variant={BackgroundVariant.Lines}/> |
| 80 | <Panel className={'space-x-4'} position="top-right"> |
| 81 | <button className={'p-[4px] rounded bg-white shadow'} onClick={addOscNode}>添加振荡器节点</button> |
| 82 | <button className={'p-[4px] rounded bg-white shadow'} onClick={addVolumeNode}>添加音量节点</button> |
| 83 | </Panel> |
| 84 | </ReactFlow> |
| 85 | </div> |
| 86 | ); |
| 87 | } |
nothing calls this directly
no outgoing calls
no test coverage detected