如何使用 UIBezierPath 创建带有数据点的曲线图? [英] How can I use a UIBezierPath to create a curved line chart with data points?

查看:30
本文介绍了如何使用 UIBezierPath 创建带有数据点的曲线图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 UIBezierPath 来创建折线图.我的目标是为这个图表制作动画并让它看起来是波浪形的".但我似乎无法获得镜像数据的路径.

I am trying to use a UIBezierPath to create a line chart. My goal is to animate this chart and have it appear to be "wavy." But I can't seem to get the path to mirror my data.

添加数据点

let dataPoints: [Double]


func wave(at elapsed: Double) -> UIBezierPath {
    let amplitude = CGFloat(50) - abs(fmod(CGFloat(elapsed/2), 3) - 1.5) * 100
    func f(_ x: Int) -> CGFloat {
        return sin(((CGFloat(dataPoints[x]*100) / bounds.width) + CGFloat(elapsed/2)) * 4 * .pi) * amplitude + bounds.midY
    }
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 0, y: f(0)))
    for x in 1..<dataPoints.count {
        path.addLine(to: CGPoint(x: CGFloat(x), y: f(x)))
    }
    return path
}

推荐答案

一些问题:

  1. 你定义了你的 f(_:),但没有使用它,而是使用了 dataPoints(我没有看到你在任何地方填充).直接使用 f 函数可能是最简单的.

  1. You defined your f(_:), but aren’t using it, but rather using dataPoints (which I don’t see you populating anywhere). It’s probably easiest to just use your f function directly.

您正在向路径添加三次贝塞尔曲线,但您的控制点是相同的数据点.这不会提供平滑.控制点实际上应该是 x 值之前和之后的点,沿着与所讨论的曲线相切的线(例如,沿着由数据点和斜率定义的线,也就是一阶导数,曲线).

You are adding cubic Bézier curves to your path, but your control points are the same data points. That will offer no smoothing. The control points really should be points before and after your x value, along the line tangent to the curve in question (e.g. the along the line defined by the data point and the slope, a.k.a. the first derivative, of your curve).

这样做并不难,但简单的解决方案是使用 addLine.如果使用足够多的数据点,它会看起来很平滑.

It wouldn’t be so hard to do this, but the easy solution is to just use addLine. If you use enough data points, it will appear to be smooth.

当你这样做时,如果只使用 12 个数据点,它不会是一个很好的平滑正弦曲线.相反,使用更大的数字(120 或 360 或其他).为了单一的正弦曲线,除非您开始看到性能问题,否则不要担心数据点的数量.

When you do this, it won’t be a nice smooth sine curve if using only 12 data points. Instead, use a much larger number (120 or 360 or whatever). For the sake of a single sine curve, don’t worry about the number of data points unless you start to see performance issues.

您的 CGPoint 值中的 x 值比您预期的要小.如果你只从 0..<12 开始,结果路径将只有 12 点宽;哈哈.使用 x 值一直穿过有问题的视图.

Your x values in your CGPoint values are smaller than you probably intended. If you only go from 0..<12, the resulting path will be only 12 points wide; lol. Use x values to go all the way across the view in question.

所以,你可能会得到类似的结果:

So, you might end up with something like:

func wave(at elapsed: Double) -> UIBezierPath {
    let amplitude = CGFloat(50) - abs(fmod(CGFloat(elapsed/2), 3) - 1.5) * 40
    func f(_ x: Int) -> CGFloat {
        return sin(((CGFloat(x) / bounds.width) + CGFloat(elapsed/2)) * 4 * .pi) * amplitude + bounds.midY
    }
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 0, y: f(0)))
    for x in 1...Int(bounds.width) {
        path.addLine(to: CGPoint(x: CGFloat(x), y: f(x)))
    }
    return path
}

将它与 CADisplayLink 结合起来更新曲线,结果是:

Marry that with a CADisplayLink to update the curve, and that yields:

这篇关于如何使用 UIBezierPath 创建带有数据点的曲线图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆