Skip to content

Commit

Permalink
Merge pull request #68 from li3zhen1/typed-proxy
Browse files Browse the repository at this point in the history
Add `GraphProxy.node(of:at:)`
  • Loading branch information
li3zhen1 authored Jan 9, 2025
2 parents 136aecd + c1eece3 commit de95585
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ struct MermaidVisualization: View {
Rectangle().fill(.clear).contentShape(Rectangle())
.withGraphDragGesture(proxy)
.onTapGesture { value in
if let nodeID = proxy.locateNode(at: .init(x: value.x, y: value.y)) {
guard let nodeID = nodeID as? String else { return }
if let nodeID = proxy.node(of: String.self, at: value) {
model.tappedNode = nodeID
}
}
Expand Down
3 changes: 1 addition & 2 deletions Sources/Grape/Gestures/GraphDragGesture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,8 @@ struct GraphDragModifier: ViewModifier {
value: DragGesture.Value
) {
if dragState == nil {
if let nodeID = graphProxy.locateNode(at: value.startLocation) {
if let nodeID = graphProxy.node(at: value.startLocation) {
dragState = .node(nodeID)

graphProxy.setNodeFixation(nodeID: nodeID, fixation: value.startLocation)
} else {
dragState = .background(start: value.location.simd)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Grape/Gestures/GraphTapGesture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extension View {
action: @escaping (AnyHashable) -> Void
) -> some View {
self.onTapGesture { value in
if let nodeID = proxy.locateNode(at: .init(x: value.x, y: value.y)) {
if let nodeID = proxy.node(at: .init(x: value.x, y: value.y)) {
action(nodeID)
}
}
Expand Down
14 changes: 11 additions & 3 deletions Sources/Grape/Modifiers/GraphProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,22 @@ public struct GraphProxy {
}

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

/// Find the type erased node ID at the given location in the viewport coordinate.
/// Returns `nil` if no node is found.
@inlinable
public func locateNode(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {
storage?.locateNode(at: locationInViewportCoordinate)
public func node(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {
storage?.node(at: locationInViewportCoordinate)
}

@inlinable
public func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?, minimumAlpha: Double = 0.5) {
public func setNodeFixation<ID: Hashable>(nodeID: ID, fixation: CGPoint?, minimumAlpha: Double = 0.5) {
storage?.setNodeFixation(nodeID: nodeID, fixation: fixation, minimumAlpha: minimumAlpha)
}

Expand Down
45 changes: 28 additions & 17 deletions Sources/Grape/Views/ForceDirectedGraphModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import SwiftUI
@MainActor
public protocol _AnyGraphProxyProtocol {
@inlinable
func locateNode(
func node(
at locationInViewportCoordinate: CGPoint
) -> AnyHashable?


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

@inlinable
func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?, minimumAlpha: Double)
func setNodeFixation<ID: Hashable>(nodeID: ID, fixation: CGPoint?, minimumAlpha: Double)

@inlinable
var kineticAlpha: Double { get nonmutating set }
Expand All @@ -32,8 +33,18 @@ public protocol _AnyGraphProxyProtocol {
}

extension ForceDirectedGraphModel: _AnyGraphProxyProtocol {

@inlinable
public func locateNode(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {
public func node<ID>(of type: ID.Type, at locationInViewportCoordinate: CGPoint) -> ID? where ID: Hashable {
if type.self == NodeID.self {
return findNode(at: locationInViewportCoordinate) as! ID?
} else {
return nil
}
}

@inlinable
public func node(at locationInViewportCoordinate: CGPoint) -> AnyHashable? {

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

@inlinable
public func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?, minimumAlpha: Double) {
public func setNodeFixation<ID>(nodeID: ID, fixation: CGPoint?, minimumAlpha: Double) {
guard let nodeID = nodeID as? NodeID else {
return
}
Expand Down Expand Up @@ -201,7 +212,7 @@ public final class ForceDirectedGraphModel<NodeID: Hashable> {
let ticksPerSecond: Double

@usableFromInline
// @MainActor
@MainActor
var scheduledTimer: Timer? = nil

@usableFromInline
Expand Down Expand Up @@ -329,6 +340,7 @@ public final class ForceDirectedGraphModel<NodeID: Hashable> {
@inlinable
deinit {
print("deinit")

let _ = MainActor.assumeIsolated {
scheduledTimer?.invalidate()
}
Expand Down Expand Up @@ -604,11 +616,11 @@ extension ForceDirectedGraphModel {
width: physicalWidth, height: physicalHeight)

let rect = CGRect(
x: center.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
y: -center.y - offset.y - textImageOffset.y, // - physicalHeight
width: physicalWidth,
height: physicalHeight
)
x: center.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
y: -center.y - offset.y - textImageOffset.y, // - physicalHeight
width: physicalWidth,
height: physicalHeight
)
cgContext.draw(
rasterizedSymbol,
in: rect
Expand Down Expand Up @@ -658,11 +670,11 @@ extension ForceDirectedGraphModel {
width: physicalWidth, height: physicalHeight)

let rect = CGRect(
x: pos.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
y: -pos.y - offset.y - textImageOffset.y, // - physicalHeight
width: physicalWidth,
height: physicalHeight
)
x: pos.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
y: -pos.y - offset.y - textImageOffset.y, // - physicalHeight
width: physicalWidth,
height: physicalHeight
)

cgContext.draw(
rasterizedSymbol,
Expand Down Expand Up @@ -692,7 +704,6 @@ extension ForceDirectedGraphModel {
let textImageOffset = textOffsetParams.alignment.textImageOffsetInCGContext(
width: physicalWidth, height: physicalHeight)


let rect = CGRect(
x: center.x + offset.x + textImageOffset.x, // - physicalWidth / 2,
y: -center.y - offset.y - textImageOffset.y, // - physicalHeight
Expand Down

0 comments on commit de95585

Please sign in to comment.