swift - 如何在标记中显示图表点 (x, y) 以外的数据?

标签 swift ios-charts

我已经想出如何修改标记中出现的文本和 x、y 值,但我不知道如何在标记中显示其他数据。

这是我目前的标记:

enter image description here

我想显示两个用于计算 y 值的值,而不是 x 和 y 值:

“5 次 @ 200 磅”


更新:换句话说,图表上显示的点是 233.3(y 值)。但我需要让标签显示用于计算图表上的点 233.3 结果的 5 和 200。


看起来我会使用 func refreshContent(entry: ChartDataEntry, highlight: Highlight) 但这需要一个 ChartDataEntry 并且我想显示的值是 不是 数据点 (ChartDataEntry)。

我查看了 Github 项目上的所有问题,我能找到的最接近解决方案的是 this thread ,但答案并不能真正帮助初级开发人员。

谁能教我如何在标记中显示非数据点数据?

更新:感谢@RazibMollick 指导我使用 ChartDataEntry 初始值设定项的解决方案,它带有一个额外的参数(ChartDataEntry(x:y :data:) ) 在我的 generatedLineData 方法中:

let numberFormatter = NumberFormatter()
let repetitions = numberFormatter.string(from: liftEvents[index].repetitions)
let weightLifted = numberFormatter.string(from: liftEvents[index].weightLifted)
let liftData = LiftData(repetitions: repetitions!, weightLifted: weightLifted!)

return ChartDataEntry(x: (thisDateInSeconds! - beginningDateInSeconds) / (3600.0 * 24.0), y: yValue, data: (liftData as AnyObject))

refreshContent(entry:highlight) 我现在有这个:

open override func refreshContent(entry: ChartDataEntry, highlight: Highlight)
{
    let unit = UserDefaults.weightUnit()
    let liftData = entry.data as! LiftData
    setLabel(String(format: "%@ reps @ %@ \(unit)", liftData.repetitions, liftData.weightLifted))
}

现在我有这个:

enter image description here

现在,如果我能让 BalloonMarker 上的那些角变圆...

最佳答案

[Swift 4],我使用了来自 here 的辅助类.

我修改了如下类(在 refreshContent 中设置你想要的字符串):

import Foundation
import Charts
open class BalloonMarker: MarkerImage
{
    open var color: UIColor?
    open var arrowSize = CGSize(width: 15, height: 11)
    open var font: UIFont?
    open var textColor: UIColor?
    open var insets = UIEdgeInsets()
    open var minimumSize = CGSize()

    fileprivate var labelns: NSString?
    fileprivate var _labelSize: CGSize = CGSize()
    fileprivate var _paragraphStyle: NSMutableParagraphStyle?
    fileprivate var _drawAttributes = [NSAttributedStringKey : Any]()

    public init(color: UIColor, font: UIFont, textColor: UIColor, insets: UIEdgeInsets)
    {
        super.init()

        self.color = color
        self.font = font
        self.textColor = textColor
        self.insets = insets

        _paragraphStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle
        _paragraphStyle?.alignment = .center
    }

    open override func offsetForDrawing(atPoint point: CGPoint) -> CGPoint
    {
        var offset = self.offset

        let chart = self.chartView

        var size = self.size

        if size.width == 0.0 && image != nil
        {
            size.width = image?.size.width ?? 0.0
        }
        if size.height == 0.0 && image != nil
        {
            size.height = image?.size.height ?? 0.0
        }

        let width = size.width
        let height = size.height
        let padding = CGFloat(8.0)
        var origin = point;
        origin.x -= width / 2;
        origin.y -= height;
        if origin.x + offset.x < 0.0
        {
            offset.x = -origin.x + padding
        }
        else if chart != nil && origin.x + width + offset.x > chart!.bounds.size.width
        {
            offset.x = chart!.bounds.size.width - origin.x - width - padding
        }

        if origin.y + offset.y < 0
        {
            offset.y = height + padding;
        }
        else if chart != nil && origin.y + height + offset.y > chart!.bounds.size.height
        {
            offset.y = chart!.bounds.size.height - origin.y - height - padding
        }

        return offset
    }

    open override func draw(context: CGContext, point: CGPoint)
    {
        if labelns == nil
        {
            return
        }
        let offset = self.offsetForDrawing(atPoint: point)
        let size = self.size

        var rect = CGRect(
            origin: CGPoint(
                x: point.x + offset.x,
                y: point.y + offset.y),
            size: size)
        rect.origin.x -= size.width / 2.0
        rect.origin.y -= size.height
        context.saveGState()

        if let color = color
        {
            context.setFillColor(color.cgColor)
            if(offset.y > 0) {
                context.beginPath()
                context.move(to: CGPoint(
                    x: rect.origin.x,
                    y: rect.origin.y + arrowSize.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0,
                    y: rect.origin.y + arrowSize.height))
                //arrow vertex
                context.addLine(to: CGPoint(
                    x: point.x,
                    y: point.y))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0,
                    y: rect.origin.y + arrowSize.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + rect.size.width,
                    y: rect.origin.y + arrowSize.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + rect.size.width,
                    y: rect.origin.y + rect.size.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x,
                    y: rect.origin.y + rect.size.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x,
                    y: rect.origin.y + arrowSize.height))
                context.fillPath()
            } else {
                context.beginPath()
                context.move(to: CGPoint(
                    x: rect.origin.x,
                    y: rect.origin.y))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + rect.size.width,
                    y: rect.origin.y))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + rect.size.width,
                    y: rect.origin.y + rect.size.height - arrowSize.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0,
                    y: rect.origin.y + rect.size.height - arrowSize.height))
                //arrow vertex
                context.addLine(to: CGPoint(
                    x: point.x,
                    y: point.y))
                context.addLine(to: CGPoint(
                    x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0,
                    y: rect.origin.y + rect.size.height - arrowSize.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x,
                    y: rect.origin.y + rect.size.height - arrowSize.height))
                context.addLine(to: CGPoint(
                    x: rect.origin.x,
                    y: rect.origin.y))
                context.fillPath()
            }
        }
        if (offset.y > 0) {
            rect.origin.y += self.insets.top + arrowSize.height
        } else {
            rect.origin.y += self.insets.top
        }
        rect.size.height -= self.insets.top + self.insets.bottom

        UIGraphicsPushContext(context)

        labelns?.draw(in: rect, withAttributes: _drawAttributes)

        UIGraphicsPopContext()

        context.restoreGState()
    }

    open override func refreshContent(entry: ChartDataEntry, highlight: Highlight)
    {
        //setLabel(String(entry.y))
        setLabel(String(format: "%.1f reps @ %.01f lb", entry.x, entry.y))
    }

    open func setLabel(_ label: String)
    {
        labelns = label as NSString

        _drawAttributes.removeAll()
        _drawAttributes[NSAttributedStringKey.font] = self.font
        _drawAttributes[NSAttributedStringKey.paragraphStyle] = _paragraphStyle
        _drawAttributes[NSAttributedStringKey.foregroundColor] = self.textColor

        _labelSize = labelns?.size(withAttributes: _drawAttributes) ?? CGSize.zero

        var size = CGSize()
        size.width = _labelSize.width + self.insets.left + self.insets.right
        size.height = _labelSize.height + self.insets.top + self.insets.bottom
        size.width = max(minimumSize.width, size.width)
        size.height = max(minimumSize.height, size.height)
        self.size = size
    }
}

然后我添加如下气球标记:

let marker:BalloonMarker = BalloonMarker(color: UIColor.black, font: UIFont(name: "Helvetica", size: 12)!, textColor: UIColor.white, insets: UIEdgeInsets(top: 7.0, left: 7.0, bottom: 7.0, right: 7.0))
        marker.minimumSize = CGSize(width: 75.0, height: 35.0)
        chartView.marker = marker

[编辑 1]

还有另一种方法见下文,您可以考虑添加额外的数据作为AnyObject并在refreshContent中获取数据值。或者您可以使用字典映射修改 BalloonMarker 类。

 ChartDataEntry(x:Double, y: Double, data: AnyObject?) 

关于swift - 如何在标记中显示图表点 (x, y) 以外的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49859911/

相关文章:

ios - 从数组中提取多个数据时如何使用 iOS 图表?

ios - 如何在条形图顶部显示条形图值?

ios - 无法加载 'Charts' 的底层模块

ios - Swift:在多个 View Controller 和数组之间保持数据副本一致

ios - 在哪里调用函数 Fill Chart Array 以减少加载时间?

swift - IOS 图表/MPAndroidChart。轴高

ios - 方法不能声明为 public,因为它的参数使用内部类型

ios - iOS 设备之间的 TCP 连接

ios - 如何实现滑动时从左向右移动的水平堆叠卡片?

json - 使用 json 在 Swift 中预测 wunderground api