ios - 如何使用 UIBezierPath 创建带有数据点的曲线图?
问题描述
我正在尝试使用 aUIBezierPath
创建折线图。我的目标是为这张图表制作动画,让它看起来像是“波浪状的”。但我似乎无法获得镜像数据的路径。
编辑:添加数据点
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
}
解决方案
几个问题:
你定义了你的
f(_:)
,但没有使用它,而是使用dataPoints
(我没有看到你在任何地方填充)。直接使用你的f
函数可能是最简单的。您正在向路径添加三次贝塞尔曲线,但您的控制点是相同的数据点。这不会提供平滑。控制点实际上应该是您的
x
值之前和之后的点,沿着与相关曲线相切的线(例如,沿着由数据点定义的线和曲线的斜率,也就是一阶导数)。这样做并不难,但简单的解决方案就是使用
addLine
. 如果你使用足够多的数据点,它会显得很平滑。当你这样做时,如果只使用 12 个数据点,它不会是一个很好的平滑正弦曲线。相反,请使用更大的数字(120 或 360 或其他)。为了一条正弦曲线,除非您开始看到性能问题,否则不要担心数据点的数量。
您的
x
价值观中的CGPoint
价值观可能比您预期的要小。如果您只从 0..<12 开始,则生成的路径将只有 12 点宽;哈哈。使用x
值一直遍历相关视图。
所以,你最终可能会得到类似的东西:
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
}
将其与 aCADisplayLink
结合以更新曲线,从而产生:
推荐阅读
- sharing - React 两个组件之间的状态同步或两个不同事物之间的更改同步
- file-io - 为什么 Linux 系统调用 read() 返回小于请求的大小?
- node.js - 使用 node.js 启动不和谐机器人的问题
- perl - Perl Gtk3::ScrolledWindow 包含多个 Gtk3::TreeView 子级。选择行时如何禁止孩子滚动到顶部?
- html - Google Maps API - 自动填充地址只能工作一次?(ASP.NET/jQuery/HTML)
- batch-file - 混淆批处理文件,使它们永远无法读取
- laravel - Laravel 中的 OAuth 中间件
- postgresql - 使用 pgx 从 Postgres 扫描 PostGIS 点时,接口 {} 是字符串,而不是 []uint8
- javascript - Set-Cookie 在 Chrome 和 Dolphin 中不起作用 - 有两个网站
- java - 我可以使用 Autowired 构造函数将模拟注入原型 bean 吗?