diff --git a/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/Lattice.swift b/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/Lattice.swift index f0ee897..bce0e96 100644 --- a/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/Lattice.swift +++ b/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/Lattice.swift @@ -57,7 +57,7 @@ struct Lattice: View { } .graphOverlay(content: { proxy in Rectangle().fill(.clear).contentShape(Rectangle()) - .withGraphDragGesture(proxy) + .withGraphDragGesture(proxy, of: Int.self) }) .toolbar { GraphStateToggle(graphStates: graphStates) diff --git a/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MermaidVisualization.swift b/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MermaidVisualization.swift index 75987a1..29dc31c 100644 --- a/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MermaidVisualization.swift +++ b/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MermaidVisualization.swift @@ -107,7 +107,7 @@ struct MermaidVisualization: View { } .graphOverlay(content: { proxy in Rectangle().fill(.clear).contentShape(Rectangle()) - .withGraphDragGesture(proxy) + .withGraphDragGesture(proxy, of: String.self) .onTapGesture { value in if let nodeID = proxy.node(of: String.self, at: value) { model.tappedNode = nodeID diff --git a/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MyRing.swift b/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MyRing.swift index 49061ee..1fa5fde 100644 --- a/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MyRing.swift +++ b/Examples/ForceDirectedGraphExample/ForceDirectedGraphExample/MyRing.swift @@ -59,7 +59,7 @@ struct MyRing: View { } .graphOverlay { proxy in Rectangle().fill(.clear).contentShape(Rectangle()) - .withGraphDragGesture(proxy, action: describe) + .withGraphDragGesture(proxy, of: Int.self, action: describe) .withGraphMagnifyGesture(proxy) } .toolbar { @@ -67,10 +67,9 @@ struct MyRing: View { } } - func describe(_ state: GraphDragState?) { + func describe(_ state: GraphDragState?) { switch state { - case .node(let anyHashable): - let id = anyHashable as! Int + case .node(let id): if draggingNodeID != id { draggingNodeID = id print("Dragging \(id)") diff --git a/Sources/Grape/Gestures/GraphDragGesture.swift b/Sources/Grape/Gestures/GraphDragGesture.swift index 785c087..49817b1 100644 --- a/Sources/Grape/Gestures/GraphDragGesture.swift +++ b/Sources/Grape/Gestures/GraphDragGesture.swift @@ -1,15 +1,15 @@ import ForceSimulation import SwiftUI -public enum GraphDragState { - case node(AnyHashable) - case background(start: SIMD2) +public enum GraphDragState { + case node(NodeID) + case background(SIMD2) } #if !os(tvOS) @usableFromInline -struct GraphDragModifier: ViewModifier { +struct GraphDragModifier: ViewModifier { @inlinable public var dragGesture: some Gesture { @@ -28,18 +28,18 @@ struct GraphDragModifier: ViewModifier { @inlinable @State - public var dragState: GraphDragState? + public var dragState: GraphDragState? @usableFromInline let graphProxy: GraphProxy @usableFromInline - let action: ((GraphDragState?) -> Void)? + let action: ((GraphDragState?) -> Void)? @inlinable init( graphProxy: GraphProxy, - action: ((GraphDragState?) -> Void)? = nil + action: ((GraphDragState?) -> Void)? = nil ) { self.graphProxy = graphProxy self.action = action @@ -62,7 +62,7 @@ struct GraphDragModifier: ViewModifier { case .background(let start): let delta = value.location.simd - start graphProxy.modelTransform.translate += delta - dragState = .background(start: value.location.simd) + dragState = .background(value.location.simd) case .none: break } @@ -79,11 +79,11 @@ struct GraphDragModifier: ViewModifier { value: DragGesture.Value ) { if dragState == nil { - if let nodeID = graphProxy.node(at: value.startLocation) { + if let nodeID = graphProxy.node(of: NodeID.self, at: value.startLocation) { dragState = .node(nodeID) graphProxy.setNodeFixation(nodeID: nodeID, fixation: value.startLocation) } else { - dragState = .background(start: value.location.simd) + dragState = .background(value.location.simd) } } else { switch dragState { @@ -92,7 +92,7 @@ struct GraphDragModifier: ViewModifier { case .background(let start): let delta = value.location.simd - start graphProxy.modelTransform.translate += delta - dragState = .background(start: value.location.simd) + dragState = .background(value.location.simd) case .none: break } @@ -105,10 +105,17 @@ struct GraphDragModifier: ViewModifier { } extension View { + + /// Attach a drag gesture to an overlay or a background view created with ``SwiftUICore/View/graphOverlay(alignment:content:)``. + /// - Parameters: + /// - proxy: The graph proxy that provides the graph context. + /// - type: The type of the node ID. The drag gesture will look for the node ID of this type. + /// - action: The action to perform when the drag gesture changes. @inlinable - public func withGraphDragGesture( + public func withGraphDragGesture( _ proxy: GraphProxy, - action: ((GraphDragState?) -> Void)? = nil + of type: NodeID.Type, + action: ((GraphDragState?) -> Void)? = nil ) -> some View { self.modifier(GraphDragModifier(graphProxy: proxy, action: action)) } diff --git a/Sources/Grape/Gestures/GraphTapGesture.swift b/Sources/Grape/Gestures/GraphTapGesture.swift index 38fdfdc..b4ad515 100644 --- a/Sources/Grape/Gestures/GraphTapGesture.swift +++ b/Sources/Grape/Gestures/GraphTapGesture.swift @@ -3,12 +3,13 @@ import SwiftUI extension View { @inlinable @available(tvOS, unavailable) - public func withGraphTapGesture( + public func withGraphTapGesture( _ proxy: GraphProxy, - action: @escaping (AnyHashable) -> Void + of type: NodeID.Type, + action: @escaping (NodeID) -> Void ) -> some View { self.onTapGesture { value in - if let nodeID = proxy.node(at: .init(x: value.x, y: value.y)) { + if let nodeID = proxy.node(of: type, at: value) { action(nodeID) } }