1

我需要根据每半秒出现一次的值绘制折线图。我已经为该图提出了我的自定义 CALayer,它存储了所有先前的行,并且每两秒重绘所有先前的行并添加一个新行。我发现这个解决方案不是最佳的,因为只需要在图层上画一条额外的线,没有理由重新绘制可能数千条之前的线。

您认为在这种情况下最好的解决方案是什么?

4

2 回答 2

1

使用您自己的NSBitmapContextUIImage作为后备商店。每当新数据进入此上下文并将图层的contents属性设置为上下文的图像时。

于 2012-10-26T13:56:59.993 回答
0

I am looking at an identical implementation. Graph updates every 500 ms. Similarly I felt uncomfortable drawing the entire graph each iteration. I implemented a solution 'similar' to what Nikolai Ruhe proposed as follows:

First some declarations:

#define TIME_INCREMENT 10
@property (nonatomic) UIImage *lastSnapshotOfPlot;

and then the drawLayer:inContext method of my CALayer delegate

- (void) drawLayer:( CALayer*)layer inContext:(CGContextRef)ctx
{

    // Restore the image of the layer from the last time through, if it exists

    if( self.lastSnapshotOfPlot )
    {
        // For some reason the image is being redrawn upside down!
        // This block of code adjusts the context to correct it.

        CGContextSaveGState(ctx);
        CGContextTranslateCTM(ctx, 0, layer.bounds.size.height);
        CGContextScaleCTM(ctx, 1.0, -1.0);

        // Now we can redraw the image right side up but shifted over a little bit
        // to allow space for the new data

        CGRect r = CGRectMake( -TIME_INCREMENT, 0, layer.bounds.size.width, layer.bounds.size.height );  
        CGContextDrawImage(ctx, r, self.lastSnapshotOfPlot.CGImage );

        // And finally put the context back the way it was

        CGContextRestoreGState(ctx); 
    }

    CGContextStrokePath(ctx);

    CGContextSetLineWidth(ctx, 2.0);
    CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor );
    CGContextBeginPath( ctx );

    // This next section is where I draw the line segment on the extreme right end
    // which matches up with the stored graph on the image.  This part of the code 
    // is application specific and I have only left it here for
    // conceptual reference.  Basically I draw a tiny line segment
    // from the last value to the new value at the extreme right end of the graph.

    CGFloat ppy = layer.bounds.size.height - _lastValue / _displayRange * layer.bounds.size.height;
    CGFloat cpy = layer.bounds.size.height - self.sensorData.currentvalue  / _displayRange * layer.bounds.size.height;

    CGContextMoveToPoint(ctx,layer.bounds.size.width - TIME_INCREMENT, ppy ); // Move to the previous point
    CGContextAddLineToPoint(ctx, layer.bounds.size.width, cpy );  // Draw to the latest point

    CGContextStrokePath(ctx);

    // Finally save the entire current layer to an image.  This will include our latest
    // drawn line segment 

    UIGraphicsBeginImageContext(layer.bounds.size);
    [layer renderInContext: UIGraphicsGetCurrentContext()];
    self.lastSnapshotOfPlot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

}

Is this the most efficient way? I have not been programming in ObjectiveC long enough to know so all suggestions/improvements welcome.

于 2012-12-01T11:03:08.707 回答