From 5fa66400e90377b11269f92a2cb45b8c8cc80393 Mon Sep 17 00:00:00 2001 From: li3zhen1 Date: Sun, 5 Nov 2023 15:02:21 -0500 Subject: [PATCH] Add Link Rendering --- README.md | 6 +-- Sources/Grape/Views/ForceDirectedGraph.swift | 40 ++++++++++++++++---- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1977f20..55533c9 100644 --- a/README.md +++ b/README.md @@ -66,15 +66,13 @@ Source code: [ForceDirectedGraph3D/ContentView.swift](https://github.com/li3zhen ## Usage -### `Grape` (WIP) - -`Grape` provides a SwiftUI view `ForceDirectedGraph`: +### `Grape` > [!IMPORTANT] > `ForceDirectedGraph` is only a minimal working example. Please refer to the next section to create a more complex view. ```swift -struct ForceDirectedGraphSwiftUIExample: View { +struct MyGraph: View { let graphController = ForceDirectedGraph2DController() var body: some View { ForceDirectedGraph(controller: graphController) { diff --git a/Sources/Grape/Views/ForceDirectedGraph.swift b/Sources/Grape/Views/ForceDirectedGraph.swift index dfd4370..a4d87d2 100644 --- a/Sources/Grape/Views/ForceDirectedGraph.swift +++ b/Sources/Grape/Views/ForceDirectedGraph.swift @@ -27,18 +27,44 @@ public struct ForceDirectedGraph: View { let centerX = cgSize.width / 2.0 let centerY = cgSize.height / 2.0 + for i in self.content.links { + let source = self.nodeIdToIndexLookup[i.id.source]! + let target = self.nodeIdToIndexLookup[i.id.target]! + + let sourceX = centerX + model.simulation.nodePositions[source].x + let sourceY = centerY + model.simulation.nodePositions[source].y + let targetX = centerX + model.simulation.nodePositions[target].x + let targetY = centerY + model.simulation.nodePositions[target].y + + context.stroke( + Path { path in + path.move(to: CGPoint(x: sourceX, y: sourceY)) + path.addLine(to: CGPoint(x: targetX, y: targetY)) + }, + with: .color(i.strokeColor), + style: StrokeStyle(lineWidth: i.strokeWidth) + ) + } + for i in model.simulation.nodePositions.indices { let node = content.nodes[i] - let x = centerX + model.simulation.nodePositions[i].x - let y = centerY + model.simulation.nodePositions[i].y + let x = centerX + model.simulation.nodePositions[i].x - node.radius + let y = centerY + model.simulation.nodePositions[i].y - node.radius - let rect = CGRect(origin: .init(x: x, y: y), size: CGSize(width: 8.0, height: 8.0)) + let rect = CGRect( + origin: .init(x: x, y: y), + size: CGSize( + width: node.radius * 2, height: node.radius * 2 + ) + ) context.fill( Path(ellipseIn: rect), with: .color(node.fill)) - context.stroke( - Path(ellipseIn: rect), with: .color(Color(nsColor: .windowBackgroundColor)), - style: StrokeStyle(lineWidth: 1.5)) + if let strokeColor = node.strokeColor { + context.stroke( + Path(ellipseIn: rect), with: .color(Color(strokeColor)), + style: StrokeStyle(lineWidth: node.strokeWidth)) + } } } } @@ -97,7 +123,7 @@ public struct ForceDirectedGraph: View { forceDescriptor.attachToSimulation(simulation) } } - + self.nodeIdToIndexLookup = lookup let model = ForceDirectedGraph2DLayoutEngine( initialSimulation: simulation