I have a layer-backed NSView. When the mouse enters the view, I want to draw a big circle wherever the mouse is. Basically track the mouse position. Unfortunately, the circle is lagging behind the actual mouse position.
I think it has something to do with implicit animations. Disabling animations for the "content" property of the layer doesn't have any effect.
begin Edit: How can I draw a circle at the position of the mouse cursor while the mouse is moving without the circle lagging behind the mouse cursor? :end Edit
Here is the code I have.
class TrackingView : NSView
{
override init(frame frameRect: NSRect)
{
super.init(frame: frameRect)
self.wantsLayer = true
}
required init?(coder: NSCoder)
{
super.init(coder: coder)
self.wantsLayer = true
}
//layer backing
override var wantsUpdateLayer : Bool { return true }
override func makeBackingLayer() -> CALayer
{
return TrackingLayer()
}
//tracking areas
override func updateTrackingAreas()
{
//remove current tracking area's
while self.trackingAreas.count > 0
{
self.removeTrackingArea(self.trackingAreas.first as! NSTrackingArea)
}
if let trackingFrames = (self.layer as? TrackingLayer)?.trackingFrames
{
for trackingFrame in trackingFrames
{
let trackingArea = NSTrackingArea(
rect: trackingFrame,
options: NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveInActiveApp | NSTrackingAreaOptions.MouseMoved,
owner: self,
userInfo: nil)
self.addTrackingArea(trackingArea)
}
}
}
//mouse
override func mouseEntered(event: NSEvent)
{
(self.layer as? TrackingLayer)?.userLocation = self.convertPoint(event.locationInWindow, fromView: nil)
}
override func mouseMoved(event: NSEvent)
{
(self.layer as? TrackingLayer)?.userLocation = self.convertPoint(event.locationInWindow, fromView: nil)
}
}
class TrackingLayer : CALayer
{
var trackingFrames : [NSRect] { return [self.frame] }
var userLocation : CGPoint? {
didSet { self.setNeedsDisplay() }
}
override init!()
{
super.init()
self.disableAnimations()
self.backgroundColor = NSColor.whiteColor().CGColor
}
override init!(layer: AnyObject!)
{
super.init(layer: layer)
self.disableAnimations()
}
required init(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
self.disableAnimations()
}
//animations
private func disableAnimations()
{
self.actions = [
"content" : NSNull(),
"sublayers" : NSNull()]
}
//drawing
override func drawInContext(context: CGContext!)
{
if var assumedUserLocation = userLocation
{
CGContextStrokeEllipseInRect(context, CGRectMake(assumedUserLocation.x-5, assumedUserLocation.y-5, 10, 10))
CGContextFillEllipseInRect(context, CGRectMake(assumedUserLocation.x-5, assumedUserLocation.y-5, 10, 10))
}
}
}