【问题标题】:Efficient way to draw a graph line by line in CALayer在CALayer中逐行绘制图形的有效方法
【发布时间】:2012-10-26 13:47:50
【问题描述】:

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

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

【问题讨论】:

    标签: ios core-graphics calayer quartz-graphics quartz-2d


    【解决方案1】:

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

    【讨论】:

    • 你说的是CGBitmapContext吗?
    【解决方案2】:

    我正在研究一个相同的实现。图表每 500 毫秒更新一次。同样,每次迭代绘制整个图表时,我都感到不舒服。我实施了一个与 Nikolai Ruhe 提出的“类似”的解决方案,如下所示:

    首先是一些声明:

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

    然后是我的 CALayer 委托的 drawLayer:inContext 方法

    - (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();
    
    }
    

    这是最有效的方法吗? 我在 ObjectiveC 中编程的时间还不够长,所以不知道所以欢迎所有建议/改进。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 1970-01-01
      相关资源
      最近更新 更多