Core Plot: Should I add CPTPlotSpaceAnnotation for plotting so the whole plot is redrawn?
I am using Core Plot to display price time series. When the user taps the graph, I show a draggable vertical line at that point. Both the time series and the drag line are CPTScatterPlot
objects within CPTXYGraph
. This works pretty well - the performance when dragging a line across the time series plot is acceptable.
The next step is to display the price and date at the point chosen by the user. The Yahoo Stocks app has a nice feature that displays the price in a label that moves as if it's attached to the top of a dragged line. I tried to reproduce this using the text displayed in CPTPlotSpaceAnnotation
. It works, but it has a huge performance impact. After some digging, I found that it CPTLayer drawInContext:
gets called multiple times - it looks like the entire graph is redrawn every time I redraw the text label (actually my logs imply it is redrawn twice).
Here is the code that draws the label (work in progress). It is called plotSpace:shouldHandlePointingDeviceDraggedEvent:atPoint:
.
- (void)displayPriceAndDateForIndex:(NSUInteger)index atPoint:(CGPoint)pointInPlotArea
{
NSNumber * theValue = [[self.graphDataSource.timeSeries objectAtIndex:index] observationValue];
// if the annotations already exist, remove them
if ( self.valueTextAnnotation ) {
[self.graph.plotAreaFrame.plotArea removeAnnotation:self.valueTextAnnotation];
self.valueTextAnnotation = nil;
}
// Setup a style for the annotation
CPTMutableTextStyle *annotationTextStyle = [CPTMutableTextStyle textStyle];
annotationTextStyle.color = [CPTColor whiteColor];
annotationTextStyle.fontSize = 14.0f;
annotationTextStyle.fontName = @"Helvetica-Bold";
// Add annotation
// First make a string for the y value
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:2];
NSString *currentValue = [formatter stringFromNumber:theValue];
NSNumber *x = [NSNumber numberWithDouble:[theDate timeIntervalSince1970]];
NSNumber *y = [NSNumber numberWithFloat:self.graphDataSource.maxValue];
NSArray *anchorPoint = [NSArray arrayWithObjects:x, y, nil];
// Then add the value annotation to the plot area
float valueLayerWidth = 50.0f;
float valueLayerHeight = 20.0f;
CPTTextLayer *valueLayer = [[CPTTextLayer alloc] initWithFrame:CGRectMake(0,0,valueLayerWidth,valueLayerHeight)];
valueLayer.text = currentValue;
valueLayer.textStyle = annotationTextStyle;
valueLayer.backgroundColor = [UIColor blueColor].CGColor;
self.valueTextAnnotation = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:self.graph.defaultPlotSpace anchorPlotPoint:anchorPoint];
self.valueTextAnnotation.contentLayer = valueLayer;
// modify the displacement if we are close to either edge
float xDisplacement = 0.0;
...
self.valueTextAnnotation.displacement = CGPointMake(xDisplacement, 8.0f);
[self.graph.plotAreaFrame.plotArea addAnnotation:self.valueTextAnnotation];
// now do the date field
...
}
Is the expected full redraw behavior? And is there a better way to manage the annotation without destroying it and recreating it every time the method is called?
You don't have to destroy and create annotations every time. Once it has been created, just update anchorPoint
. Removing and adding annotation is probably due to constant redrawing.