MacOS 中的图表标记视图不显示

Charts MarkerView in MacOS won't display

提问人:RL2000 提问时间:3/18/2023 更新时间:3/18/2023 访问量:70

问:

这个问题是关于 DanielGindi/Charts 的,但我认为即使你不熟悉这个库,一些渲染知识也可能会有所帮助。NSViewCharts

我在 MacOS 项目中使用,但无法正确显示。我已将 ChartsDemo-iOS 项目复制到 ChartsDemo-macOS,以便在 MacOS 中使用它。但是,当我单击图表中的值时,标记永远不会出现在视图中。ChartsMarkerViewRadarMarkerViewRadarDemoViewController

以下是完整的实现:RadarMarkerViewMac

public class RadarMarkerViewMac: MarkerView {
  @IBOutlet var label: NSTextField!

  public override func awakeFromNib() {
    self.offset.x = -self.frame.size.width / 2.0
    self.offset.y = -self.frame.size.height - 7.0
  }

  public override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
    label.stringValue = String.init(format: "%.3f %%", (entry.y))
    _ = self // see note 2
    layout() // see note 1
  }
}

如果您查看原始的 RadarMarkerView,就会发现只有两个值得注意的变化:

  1. layoutIfNeeded()更改为 因为 中不存在前一个函数。layout()NSView
  2. 我把这条线放在那里,这样我就可以添加一个断点来查看是否正确绘制(当暂停断点时,将鼠标悬停在 ,然后单击眼球按钮查看视图)。selfself

我发现的奇怪事情是:单击图表会突出显示所选值,但不显示标记。但是,当我在行上放置一个断点,然后使用预览弹出窗口查看时,我看到视图很好......然后,一旦我继续运行应用程序,标记就会在所有后续选择中按应有的方式显示在图表中,即使禁用了断点也是如此。layout()self

我认为,同样需要注意的是,如果我输入断点并且没有显示预览,则标记将不会显示在图表上。

我认为这与渲染有关,但我无法使应用程序在此处正常运行。你能帮忙吗?NSView

macOS NS查看 IOS 图表

评论


答:

1赞 Stephan Schlecht 3/18/2023 #1

仅复制 是不够的。RadarMarkerView

您需要为 macOS 创建相应的 xib。在 in 中加载来自 xib 的视图,并将其添加为可见区域之外的子视图,以便可以渲染它:RadarDemoViewControllerviewDidLoad

let marker = RadarMarkerView.viewFromXib()!
marker.chartView = radarChartView
radarChartView.marker = marker

self.view.addSubview(marker)
marker.frame = NSRect(x: -100, y: -100, width: 64, height: 64)

正如在 MarkerView 中看到的那样,使用了一个属性,它基本上对应于 .nsuiLayerself.layer

因此,您需要指定希望视图使用图层作为其后备存储。

public required init?(coder decoder: NSCoder) {
    super.init(coder: decoder)
    wantsLayer = true
}

您可以定义偏移量(取决于视图的大小):

open override func offsetForDrawing(atPoint point: CGPoint) -> CGPoint {
    return CGPoint(x: -36, y: -40)
}

在指定视图需要布局阶段才能绘制refreshContent

needsLayout = true

所以完整的看起来像这样:RadarMarkerView

import AppKit
import Charts

public class RadarMarkerView: MarkerView {
    @IBOutlet var label: NSTextField!

    public required init?(coder decoder: NSCoder) {
        super.init(coder: decoder)
        wantsLayer = true
    }

    open override func draw(context: CGContext, point: CGPoint) {
//        NSColor.red.setFill()
//        NSRect(x: point.x - 32, y: point.y - 32, width: 64, height: 64).fill()
        super.draw(context: context, point: point)
    }

    open override func offsetForDrawing(atPoint point: CGPoint) -> CGPoint {
        return CGPoint(x: -36, y: -40)
    }


    public override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
        label.stringValue = String.init(format: "%d %%", Int(round(entry.y)))
        needsLayout = true
    }
}

请注意 的覆盖。为了简化调试,可以通过编程方式绘制一个红色矩形(只需取消注释两行即可)。draw(context:point:)

测试

marker test

如您所见,然后显示标记。

评论

1赞 RL2000 3/18/2023
匪夷所思!谢谢你。我已经制作了 xib,但它正在将标记视图添加到图表视图并添加 wantsLayer 才能解决问题。