Skip to content

Commit de95585

Browse files
authored
Merge pull request #68 from li3zhen1/typed-proxy
Add `GraphProxy.node(of:at:)`
2 parents 136aecd + c1eece3 commit de95585

File tree

5 files changed

+42
-25
lines changed

5 files changed

+42
-25
lines changed

Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MermaidVisualization.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,7 @@ struct MermaidVisualization: View {
109109
Rectangle().fill(.clear).contentShape(Rectangle())
110110
.withGraphDragGesture(proxy)
111111
.onTapGesture { value in
112-
if let nodeID = proxy.locateNode(at: .init(x: value.x, y: value.y)) {
113-
guard let nodeID = nodeID as? String else { return }
112+
if let nodeID = proxy.node(of: String.self, at: value) {
114113
model.tappedNode = nodeID
115114
}
116115
}

Sources/Grape/Gestures/GraphDragGesture.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,8 @@ struct GraphDragModifier: ViewModifier {
7979
value: DragGesture.Value
8080
) {
8181
if dragState == nil {
82-
if let nodeID = graphProxy.locateNode(at: value.startLocation) {
82+
if let nodeID = graphProxy.node(at: value.startLocation) {
8383
dragState = .node(nodeID)
84-
8584
graphProxy.setNodeFixation(nodeID: nodeID, fixation: value.startLocation)
8685
} else {
8786
dragState = .background(start: value.location.simd)

Sources/Grape/Gestures/GraphTapGesture.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ extension View {
88
action: @escaping (AnyHashable) -> Void
99
) -> some View {
1010
self.onTapGesture { value in
11-
if let nodeID = proxy.locateNode(at: .init(x: value.x, y: value.y)) {
11+
if let nodeID = proxy.node(at: .init(x: value.x, y: value.y)) {
1212
action(nodeID)
1313
}
1414
}

Sources/Grape/Modifiers/GraphProxy.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,22 @@ public struct GraphProxy {
1919
}
2020

2121
extension GraphProxy: _AnyGraphProxyProtocol {
22+
/// Find the node ID at the given location in the viewport coordinate, with specific type.
23+
/// Returns `nil` if no node is found or the node is not of the specified type.
24+
@inlinable
25+
public func node<ID>(of type: ID.Type, at locationInViewportCoordinate: CGPoint) -> ID? where ID : Hashable {
26+
storage?.node(of: type, at: locationInViewportCoordinate)
27+
}
2228

29+
/// Find the type erased node ID at the given location in the viewport coordinate.
30+
/// Returns `nil` if no node is found.
2331
@inlinable
24-
public func locateNode(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {
25-
storage?.locateNode(at: locationInViewportCoordinate)
32+
public func node(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {
33+
storage?.node(at: locationInViewportCoordinate)
2634
}
2735

2836
@inlinable
29-
public func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?, minimumAlpha: Double = 0.5) {
37+
public func setNodeFixation<ID: Hashable>(nodeID: ID, fixation: CGPoint?, minimumAlpha: Double = 0.5) {
3038
storage?.setNodeFixation(nodeID: nodeID, fixation: fixation, minimumAlpha: minimumAlpha)
3139
}
3240

Sources/Grape/Views/ForceDirectedGraphModel.swift

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import SwiftUI
66
@MainActor
77
public protocol _AnyGraphProxyProtocol {
88
@inlinable
9-
func locateNode(
9+
func node(
1010
at locationInViewportCoordinate: CGPoint
1111
) -> AnyHashable?
1212

13-
13+
@inlinable
14+
func node<ID: Hashable>(of type: ID.Type, at locationInViewportCoordinate: CGPoint) -> ID?
1415

1516
@inlinable
16-
func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?, minimumAlpha: Double)
17+
func setNodeFixation<ID: Hashable>(nodeID: ID, fixation: CGPoint?, minimumAlpha: Double)
1718

1819
@inlinable
1920
var kineticAlpha: Double { get nonmutating set }
@@ -32,8 +33,18 @@ public protocol _AnyGraphProxyProtocol {
3233
}
3334

3435
extension ForceDirectedGraphModel: _AnyGraphProxyProtocol {
36+
3537
@inlinable
36-
public func locateNode(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {
38+
public func node<ID>(of type: ID.Type, at locationInViewportCoordinate: CGPoint) -> ID? where ID: Hashable {
39+
if type.self == NodeID.self {
40+
return findNode(at: locationInViewportCoordinate) as! ID?
41+
} else {
42+
return nil
43+
}
44+
}
45+
46+
@inlinable
47+
public func node(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {
3748

3849
// Find from rich label first
3950
if let nodeIDFromRichLabel = findNodeFromRichLabel(
@@ -52,7 +63,7 @@ extension ForceDirectedGraphModel: _AnyGraphProxyProtocol {
5263
}
5364

5465
@inlinable
55-
public func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?, minimumAlpha: Double) {
66+
public func setNodeFixation<ID>(nodeID: ID, fixation: CGPoint?, minimumAlpha: Double) {
5667
guard let nodeID = nodeID as? NodeID else {
5768
return
5869
}
@@ -201,7 +212,7 @@ public final class ForceDirectedGraphModel<NodeID: Hashable> {
201212
let ticksPerSecond: Double
202213

203214
@usableFromInline
204-
// @MainActor
215+
@MainActor
205216
var scheduledTimer: Timer? = nil
206217

207218
@usableFromInline
@@ -329,6 +340,7 @@ public final class ForceDirectedGraphModel<NodeID: Hashable> {
329340
@inlinable
330341
deinit {
331342
print("deinit")
343+
332344
let _ = MainActor.assumeIsolated {
333345
scheduledTimer?.invalidate()
334346
}
@@ -604,11 +616,11 @@ extension ForceDirectedGraphModel {
604616
width: physicalWidth, height: physicalHeight)
605617

606618
let rect = CGRect(
607-
x: center.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
608-
y: -center.y - offset.y - textImageOffset.y, // - physicalHeight
609-
width: physicalWidth,
610-
height: physicalHeight
611-
)
619+
x: center.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
620+
y: -center.y - offset.y - textImageOffset.y, // - physicalHeight
621+
width: physicalWidth,
622+
height: physicalHeight
623+
)
612624
cgContext.draw(
613625
rasterizedSymbol,
614626
in: rect
@@ -658,11 +670,11 @@ extension ForceDirectedGraphModel {
658670
width: physicalWidth, height: physicalHeight)
659671

660672
let rect = CGRect(
661-
x: pos.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
662-
y: -pos.y - offset.y - textImageOffset.y, // - physicalHeight
663-
width: physicalWidth,
664-
height: physicalHeight
665-
)
673+
x: pos.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
674+
y: -pos.y - offset.y - textImageOffset.y, // - physicalHeight
675+
width: physicalWidth,
676+
height: physicalHeight
677+
)
666678

667679
cgContext.draw(
668680
rasterizedSymbol,
@@ -692,7 +704,6 @@ extension ForceDirectedGraphModel {
692704
let textImageOffset = textOffsetParams.alignment.textImageOffsetInCGContext(
693705
width: physicalWidth, height: physicalHeight)
694706

695-
696707
let rect = CGRect(
697708
x: center.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
698709
y: -center.y - offset.y - textImageOffset.y, // - physicalHeight

0 commit comments

Comments
 (0)