2015-10-14 54 views
0

我想在OSX中使用Cocoa和Quartz框架使用NSBezierPath實現圖形繪製視圖,並添加/刪除數據點。CALayer drawinContext called @ 60fps,但查看更新圖形@ 1fps

在drawRect中這樣做的效果很好,因爲圖形經常更新,但當我需要增加總數據點/採樣率時遇到性能問題。

我決定移動到drawLayer:inContext:但是因爲函數在60fps時被調用,當函數調用時視圖不會更新圖形,而是更新爲1fps。

我在這裏做錯了什麼?

class CustomDrawLayer: CALayer { 


convenience init(view: NSView, drawsAsynchronously : Bool = false) { 
    self.init() 
    self.bounds = view.bounds 
    self.anchorPoint = CGPointZero 
    self.opaque = false 
    self.frame = view.frame 
    self.drawsAsynchronously = drawsAsynchronously 

    //  for multiple draws in hosting view 
    //  self.delegate = self 

} 

override func actionForLayer(layer: CALayer, forKey event: String) -> CAAction? { 
    return nil 
}} 

override func drawLayer(layer: CALayer, inContext ctx: CGContext) { 

    if layer == self.layer { 
     Swift.print("axes drawing") 
     graphBounds.origin = self.frame.origin 
     graphAxes.drawAxesInRect(graphBounds, axeOrigin: plotOrigin, xPointsToShow: CGFloat(totalSecondsToDisplay), yPointsToShow: CGFloat(totalChannelsToDisplay)) 
    } 

    if layer == self.board { 
     Swift.print(1/NSDate().timeIntervalSinceDate(fpsTimer)) 
     fpsTimer = NSDate() 
     drawPointsInGraph(graphAxes, context: ctx) 

    } 
} 

    func drawPointsInGraph(axes: AxesDrawer, context: CGContext) 
    { 
      color.set() 

      var x : CGFloat = 0 
      var y : CGFloat = 0 

      for var channel = 0; channel < Int(totalChannelsToDisplay); channel++ { 

       path.removeAllPoints() 

       var visibleIndex = (dirtyRect.origin.x - axes.position.x)/(axes.pointsPerUnit.x/samplingRate) 
       if visibleIndex < 2 { 
        visibleIndex = 2 
       } 
       for var counter = Int(visibleIndex); counter < dataStream![channel].count; counter++ { 

        if dataStream![channel][counter] == 0 { 
         if path.elementCount > 0 { 
          path.stroke() 
         } 

         break 
        } 


        let position = axes.position 
        let ppY = axes.pointsPerUnit.y 
        let ppX = axes.pointsPerUnit.x 

        let channelYLocation = CGFloat(channel) 

        x = position.x + CGFloat(counter-1) * (ppX/samplingRate) 
        y = ((channelYLocation * ppY) + position.y) + (dataStream![channel][counter-1] * (ppY)) 
        path.moveToPoint(CGPoint(x: align(x), y: align(y))) 

        x = position.x + CGFloat(counter) * (ppX/samplingRate) 
        y = ((channelYLocation * ppY) + position.y) + (dataStream![channel][counter] * (ppY)) 


        path.lineToPoint(CGPoint(x: align(x), y: align(y))) 




        if x > (axes.position.x + axes.bounds.width) * 0.9 { 

         graphAxes.forwardStep = 5 
         dirtyRect = graphBounds 

         for var c = 0; c < Int(totalChannelsToDisplay); c++ { 
          for var i = 0; i < Int(samplingRate) * graphAxes.forwardStep; i++ 
          { 
           dataStream![c][i] = 0 
          } 

         } 

         return 
        } 


       } 



       path.stroke() 

     } 

     if inLiveResize { 
      dirtyRect = graphBounds 
     } else { 
      dirtyRect.origin.x = x 
      dirtyRect.origin.y = bounds.minY 
      dirtyRect.size.width = 10 
      dirtyRect.size.height = bounds.height 
     } 


    } 

回答

1

你應該以60Hz的頻率調用一個函數是非常罕見的。在任何情況下,您都不應該嘗試在60 Hz時調用繪圖功能;這在可可中從來都沒有意義。如果你的意思是「在屏幕刷新間隔時間」,請參見CADisplayLink,它專門構建爲允許您按屏幕刷新間隔進行繪製。這可能比60Hz慢。如果您試圖準確地繪製60 Hz,則可能會出現不同步並導致動畫跳動。但這真的只適用於實時視頻等。如果你有什麼,那麼這是工具,但它聽起來並不像。

這很難理解你的代碼。目前還不清楚你的60fps在哪裏。但是我假設你想要做的是動畫繪製圖表。如果是這樣,正如Mark F所記錄的,請參閱CAShapeLayer。它具有內置的自動路徑動畫,而且絕對是你想要的。它會自動處理時間並與屏幕刷新和GPU優化同步,以及許多其他您不應該嘗試解決的問題。

即使CAShapeLayer不是您想要的,您應該查看核心動畫,該動畫旨在與您一起動畫值並根據需要重繪。例如,它會自動處理在多個內核上渲染您的圖層,這將顯着提高性能。有關更多信息,請參見Animating Custom Layer Properties

1

如果您的路徑需要頻繁繪製,請查看CAShapeLayer,您可以在其中更改路徑屬性。這將被硬件加速並比drawRect或drawLayer快得多。