Background: I am trying to have a view rotate to face the mouse at all times.
Details of issue: Moving the view based solely on the mouse moving left or right or on up or down works fine (see version 1). But using both at the same time (non-linear or arc motion with the mouse) fails to work as soon as the mouse arcs down (as y goes negative) and around (as x goes negative) and the position of the view regresses.
For this I am attempting to dynamically switch rotation values from negative to positive depending on what side of the screen the mouse is on (see version 2). But this feels like a poor implementation and is quite buggy.
Question: How can I better do this?
I am basing my cursor fetching code off of here.
Version 1-
Problem: moving the view based solely on the mouse moving left or right or on up or down works fine but this issue occurs when trying to move the mouse in a non-linear way:
import SwiftUI
struct ContentView: View {
var window: NSWindow! = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
var mouseLocation: NSPoint { NSEvent.mouseLocation }
var location: NSPoint { window.mouseLocationOutsideOfEventStream }
@State var position: NSPoint = NSPoint.init()
var body: some View {
GeometryReader { geometry in
VStack {
Rectangle()
.fill(Color.red)
.frame(width: 200, height: 200)
.rotationEffect(
(self.position.y > 60) ?
.degrees(Double(self.position.x) / 2)
: .degrees(Double(self.position.x) / 2)
)
.rotationEffect(
(self.position.x > 320) ?
.degrees(Double(self.position.y * -1))
: .degrees(Double(self.position.y) / 2)
)
}.frame(width: geometry.size.width, height: geometry.size.height)
.onAppear() {
//Setup
self.window.center();
self.window.setFrameAutosaveName("Main Window")
/* Get mouse location on movement*/
NSEvent.addLocalMonitorForEvents(matching: [.mouseMoved]) {
self.position = self.location //Save location
print("mouse location:", Double(self.position.x), Double(self.position.y))
return $0
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
Version 2- kind of works but is buggy:
import SwiftUI
struct ContentView: View {
var window: NSWindow! = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
var mouseLocation: NSPoint { NSEvent.mouseLocation }
var location: NSPoint { window.mouseLocationOutsideOfEventStream }
@State var position: NSPoint = NSPoint.init()
var body: some View {
GeometryReader { geometry in
VStack {
Rectangle()
.fill(Color.red)
.frame(width: 200, height: 200)
.rotationEffect(
(self.position.x > 181) ?
.degrees(Double(self.position.x) / 2)
: .degrees(Double(self.position.x * -1) / 2)
)
.rotationEffect(
(self.position.x > 181) ?
.degrees(Double(self.position.y * -1) / 2)
: .degrees(Double(self.position.y) / 2)
)
}.frame(width: geometry.size.width, height: geometry.size.height)
.onAppear() {
//Setup
self.window.center();
self.window.setFrameAutosaveName("Main Window")
/* Get mouse location on movement*/
NSEvent.addLocalMonitorForEvents(matching: [.mouseMoved]) {
self.position = self.location //Save location
print("mouse location:", Double(self.position.x), Double(self.position.y))
return $0
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}