Skip to content

Commit

Permalink
Merge pull request #67 from li3zhen1/ForceDescriptor<NodeID>
Browse files Browse the repository at this point in the history
Fix drag freezing
  • Loading branch information
li3zhen1 authored Dec 30, 2024
2 parents 80bb099 + 6bc5743 commit b161b33
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Grape

struct Lattice: View {

let width = 20
let width = 30
let edge: [(Int, Int)]

@State var graphStates = ForceDirectedGraphState(
Expand All @@ -33,7 +33,6 @@ struct Lattice: View {
self.edge = edge
}

@inlinable
var body: some View {
ForceDirectedGraph(states: graphStates) {

Expand All @@ -51,11 +50,15 @@ struct Lattice: View {

} force: {
.link(
originalLength: .constant(0.8),
originalLength: 0.8,
stiffness: .weightedByDegree { _, _ in 1.0 }
)
.manyBody(strength: -0.8)
}
.graphOverlay(content: { proxy in
Rectangle().fill(.clear).contentShape(Rectangle())
.withGraphDragGesture(proxy)
})
.toolbar {
GraphStateToggle(graphStates: graphStates)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct MermaidVisualization: View {

} force: {
.manyBody()
.link(originalLength: .constant(70))
.link(originalLength: 70.0)
.center()
} emittingNewNodesWithStates: { id in
KineticState(position: getInitialPosition(id: id, r: 100))
Expand All @@ -111,7 +111,6 @@ struct MermaidVisualization: View {
.onTapGesture { value in
if let nodeID = proxy.locateNode(at: .init(x: value.x, y: value.y)) {
guard let nodeID = nodeID as? String else { return }
print(nodeID)
model.tappedNode = nodeID
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ struct MiserableGraph: View {
.manyBody(strength: -20)
.center()
.link(
originalLength: .constant(35.0),
originalLength: 35.0,
stiffness: .weightedByDegree { _, _ in 1.0}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,44 @@ struct MyRing: View {

@State var graphStates = ForceDirectedGraphState()

@State var draggingNodeID: Int? = nil

static let storkeStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, lineJoin: .round)

var body: some View {

ForceDirectedGraph(states: graphStates) {
Series(0..<20) { i in

NodeMark(id: 3 * i + 0)
.symbolSize(radius: 6.0)
.foregroundStyle(.green)
.stroke(.clear)
.stroke(3*i+0 == draggingNodeID ? .black : .clear, Self.storkeStyle)

NodeMark(id: 3 * i + 1)
.symbol(.pentagon)
.symbolSize(radius:10)
.foregroundStyle(.blue)
.stroke(.clear)
.stroke(3*i+1 == draggingNodeID ? .black : .clear, Self.storkeStyle)

NodeMark(id: 3 * i + 2)
.symbol(.circle)
.symbolSize(radius:6.0)
.foregroundStyle(.yellow)
.stroke(.clear)
.stroke(3*i+2 == draggingNodeID ? .black : .clear, Self.storkeStyle)

LinkMark(from: 3 * i + 0, to: 3 * i + 1)
LinkMark(from: 3 * i + 1, to: 3 * i + 2)

LinkMark(from: 3 * i + 0, to: 3 * ((i + 1) % 20) + 0)
LinkMark(from: 3 * i + 1, to: 3 * ((i + 1) % 20) + 1)
LinkMark(from: 3 * i + 2, to: 3 * ((i + 1) % 20) + 2)


}
.stroke(
.black,
StrokeStyle(lineWidth: 1.5, lineCap: .round, lineJoin: .round)
)
.stroke(.black, Self.storkeStyle)

} force: {
.manyBody(strength: -15)
.link(
originalLength: .constant(20.0),
originalLength: 20.0,
stiffness: .weightedByDegree { _, _ in 3.0}
)
.center()
Expand All @@ -69,10 +70,16 @@ struct MyRing: View {
func describe(_ state: GraphDragState?) {
switch state {
case .node(let anyHashable):
print("Dragging \(anyHashable as! Int)")
let id = anyHashable as! Int
if draggingNodeID != id {
draggingNodeID = id
print("Dragging \(id)")
}
case .background(let start):
draggingNodeID = nil
print("Dragging \(start)")
case nil:
draggingNodeID = nil
print("Drag ended")
}
}
Expand Down
23 changes: 21 additions & 2 deletions Sources/Grape/Descriptors/ForceDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ public enum NodeAttribute<NodeID: Hashable, Attribute> {
case constant(Attribute)
}

extension NodeAttribute: ExpressibleByFloatLiteral where Attribute == Double {
@inlinable
public init(floatLiteral value: Double) {
self = .constant(value)
}
}

extension NodeAttribute {
@inlinable
func makeCompactRepresentation(nodeIDs: [NodeID]) -> ForceSimulation.AttributeDescriptor<Attribute> {
Expand Down Expand Up @@ -270,14 +277,26 @@ public struct ManyBodyForce<NodeID: Hashable>: _ForceDescriptor {

public struct LinkForce<NodeID: Hashable>: _ForceDescriptor {

public enum Stiffness {
public enum Stiffness: ExpressibleByFloatLiteral {
case constant(Double)
case weightedByDegree((EdgeID<NodeID>, LinkLookup<NodeID>) -> Double)

@inlinable
public init(floatLiteral value: Double) {
self = .weightedByDegree({ _, _ in
value
})
}
}

public enum LinkLength {
public enum LinkLength: ExpressibleByFloatLiteral {
case constant(Double)
case varied((EdgeID<NodeID>, LinkLookup<NodeID>) -> Double)

@inlinable
public init(floatLiteral value: Double) {
self = .constant(value)
}
}
public var stiffness: Stiffness
public var originalLength: LinkLength
Expand Down
1 change: 1 addition & 0 deletions Sources/Grape/Gestures/GraphDragGesture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct GraphDragModifier: ViewModifier {
if dragState == nil {
if let nodeID = graphProxy.locateNode(at: value.startLocation) {
dragState = .node(nodeID)

graphProxy.setNodeFixation(nodeID: nodeID, fixation: value.startLocation)
} else {
dragState = .background(start: value.location.simd)
Expand Down
4 changes: 2 additions & 2 deletions Sources/Grape/Modifiers/GraphProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ extension GraphProxy: _AnyGraphProxyProtocol {
}

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

@inlinable
Expand Down
16 changes: 11 additions & 5 deletions Sources/Grape/Views/ForceDirectedGraphModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public protocol _AnyGraphProxyProtocol {
func locateNode(at locationInViewportCoordinate: CGPoint) -> AnyHashable?

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

@inlinable
var kineticAlpha: Double { get nonmutating set }
Expand Down Expand Up @@ -38,10 +38,16 @@ extension ForceDirectedGraphModel: _AnyGraphProxyProtocol {
}

@inlinable
public func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?) {
public func setNodeFixation(nodeID: some Hashable, fixation: CGPoint?, minimumAlpha: Double) {
guard let nodeID = nodeID as? NodeID else {
return
}

simulationContext.storage.kinetics.alpha = max(
simulationContext.storage.kinetics.alpha,
minimumAlpha
)

let newLocationInSimulation: SIMD2<Double>? =
if let fixation {
finalTransform.invert(fixation.simd)
Expand All @@ -58,8 +64,8 @@ extension ForceDirectedGraphModel: _AnyGraphProxyProtocol {
get {
simulationContext.storage.kinetics.alpha
}
set {
simulationContext.storage.kinetics.alpha = newValue
_modify {
yield &simulationContext.storage.kinetics.alpha
}
}
}
Expand Down Expand Up @@ -720,7 +726,7 @@ extension ForceDirectedGraphModel {
count: self.simulationContext.storage.kinetics.position.count
)
}
debugPrint("[REVIVED]")
debugPrint("Graph state revived. Note this might cause expensive rerendering when combined with `richLabel` with unstable id.")
}

}

0 comments on commit b161b33

Please sign in to comment.