Core plot mouseMoved
Asked Answered
E

1

4

I would like to show (annotate) values in a scatterplot as the mouse is moved/hovering over a symbol or line. I understand this question has been asked before but I can only find answers that require the user to click the plot to show this information. I have tried to implement the mouseMoved method in my plotView delegate:

- (void)mouseMoved:(NSEvent *)theEvent
{
    NSPoint location = [hostingView convertPoint: [theEvent locationInWindow] fromView: nil];
    CGPoint mouseLocation = NSPointToCGPoint(location);
    CGPoint pointInHostedGraph = [hostingView.layer convertPoint: mouseLocation toLayer:  plotItem.graph.plotAreaFrame.plotArea];

    NSUInteger index = [self.plotItem.dataSourceLinePlot indexOfVisiblePointClosestToPlotAreaPoint: pointInHostedGraph];
    NSLog(@"test: %lu",(unsigned long)index);

}

Here, plotItem is a subclass of NSObject and defined like PlotItem.h in the example and hosting view is an instance of CPTGraphHostingView. I also add:

    CPTGraphHostingView *hostedlayer=[self.plotItem updateView:hostingView height:hostingView.frame.size.height width:hostingView.frame.size.width];

    [self.plotItem renderInView:hostedlayer withTheme:theme animated:YES withData:self.myFlattenedNodes];

    hostedlayer.window.acceptsMouseMovedEvents = YES;
    [hostedlayer.window makeFirstResponder:hostingView];

But my mouseMoved method does not get called. What am I doing wrong here as I am unable to get mouseMoved to respond to my hovering. do I need to add a NSTrackingArea to hostedLayer ? Suggestions are appreciated. T

Update and solution: I followed Erics' suggestion and subclassed my CPTGraphHostingView where I implemented the following:

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.window.acceptsMouseMovedEvents = YES;
        [self.window makeFirstResponder:self];

        area = [[NSTrackingArea alloc] initWithRect:self.frame
                                            options: (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow| NSTrackingActiveAlways)
                                              owner:self userInfo:nil];

        [self addTrackingArea:area];
        [self becomeFirstResponder];
    }
    return self;
}

- (void)updateTrackingAreas {
    [self removeTrackingArea:area];
    area = [[NSTrackingArea alloc] initWithRect:self.frame
                                    options: (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow| NSTrackingActiveAlways)
                                      owner:self userInfo:nil];
    [self addTrackingArea:area];
}

- (void)mouseMoved:(NSEvent *)theEvent
{
    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
    CGPoint mouseLocation = NSPointToCGPoint(location);
    [self setLocationOfMouse:[self.layer convertPoint: mouseLocation toLayer:nil]];
}

-(void) dealloc{
    [self removeTrackingArea:area];
}

I also defined to properties of the class:

CGPoint locationOfMouse;
NSTrackingArea *area;

In my controller I added an observer for the locationOfMouse property:

    [self.plotItem.graphHostingView addObserver:self
                        forKeyPath:@"locationOfMouse"
                           options:0
                           context:NULL];

Which triggered my method that draws the annotation:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
     if ( [keyPath isEqualToString:@"locationOfMouse"] ) {
        CGPoint location = self.plotItem.graphHostingView.locationOfMouse;
        [self.plotItem mouseMovedOverGraph:location];    
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object
                           change:change context:context];
    }
} 
Elsyelton answered 17/2, 2014 at 0:50 Comment(2)
have you set the delegate to self?Kinlaw
Yes the delegate is set to self.Elsyelton
H
1

Core Plot doesn't pass mouse moved events to any of its delegates. Subclass CPTGraphHostingView (which is a subclass of NSView) and implement the -mouseMoved: method there. Core Plot only uses the mouse down, dragged, and up events so you won't interfere with any of the built-in event handling.

Hurd answered 17/2, 2014 at 1:38 Comment(2)
@ErikSkroch Thanks for the suggestion! It worked nicely. However, your comment made me wonder if I am doing something I should not be doing that may lead to problems? Is there a particular reason as to why Core Plot do not want to include mouseMoved? Thanks again! T.Elsyelton
Core Plot uses -mouseDragged: for plot scrolling. We didn't need -mouseMoved: for anything.Hurd

© 2022 - 2024 — McMap. All rights reserved.