xcode - 使用 1000 多个数据点在 Swift 中绘制折线图

标签 xcode macos swift drawing linechart

所以我有自定义 View ,我正在尝试在那里绘制折线图。首先我绘制 xGrid、yGrid 和中间线。这是我执行此操作的功能:

var width: CGFloat = 400
var height: CGFloat = 200
var xLines: CGFloat = 20
var yLines: CGFloat = 10
let color = NSColor.blackColor()

func drawMiddleLine() {
    let middleHeight = height / 2
    var context = NSGraphicsContext.currentContext()?.CGContext
    CGContextSetStrokeColorWithColor(context, color.CGColor)
    CGContextSetLineWidth(context, 2)
    CGContextMoveToPoint(context, 0, middleHeight)
    CGContextAddLineToPoint(context, width, middleHeight)
    CGContextStrokePath(context)
}

func drawYGrid() {
    let space = height / yLines
    var context = NSGraphicsContext.currentContext()?.CGContext
    CGContextSetStrokeColorWithColor(context, color.CGColor)
    for index in 0...Int(yLines) {
        CGContextMoveToPoint(context, width, (CGFloat(index) * space))
        CGContextAddLineToPoint(context, 0, (CGFloat(index) * space))
    }
    CGContextStrokePath(context)
}

func drawXGrid() {
    let space = width / xLines
    var context = NSGraphicsContext.currentContext()?.CGContext
    CGContextSetStrokeColorWithColor(context, color.CGColor)
    for index in 0...Int(xLines) {
        CGContextMoveToPoint(context, (CGFloat(index) * space), self.bounds.height)
        CGContextAddLineToPoint(context, CGFloat(index) * space, 0)
    }
    CGContextStrokePath(context)
}

现在我有了宽度是高度两倍的基本网格。现在我想缩放我的 y 轴,所以我要缩放我的数据(在这个例子中,我只取最大正数):

func getMaxValue(data: Array<CGFloat>) ->CGFloat {
    let max = maxElement(data)
    return max
}

现在我缩放我的 y 轴:

func scaleYAxis(data: Array<CGFloat>) ->Array<CGFloat> {
    let maxValue = getMaxValue(data)
    var factor = height / maxValue / 4
    var scaledY = data.map({datum -> CGFloat in
        var newValue = datum * factor
        return newValue
        })
    return scaledY
}

但是当我用太多数据点画线时,我的画会变得一团糟,因为数据点太多了。当有大约 50 个数据点时就可以了。

例如,我想在结果中得到这样的东西:JavaScript linechart with many many datapoints

有什么想法可以在 Swift 中实现吗?

我的画法是这样的:

func drawLine(data: Array<CGFloat>) {
    var path = CGPathCreateMutable()
    var middleHeight = height / 2
    CGPathMoveToPoint(path, nil, 0, middleHeight)
    var scaledY = sclaleYAxis(data)

    for index in 0..<data.count {
        var xSpot = data[index]
        var ySpot = middleHeight + scaledY[index]

        CGPathAddLineToPoint(path, nil, xSpot, ySpot)
    }
    var layer = CAShapeLayer()
    layer.frame = self.bounds
    layer.path = path
    layer.strokeColor = NSColor.greenColor().CGColor
    layer.fillColor = nil
    layer.lineWidth = 3
    self.layer?.addSublayer(layer)

    // I Have lineLayerStore and I delete all lines when it is needed
    lineLayerStore.append(layer)
}

最佳答案

如果不看屏幕截图,我无法理解确切的问题是什么,但数据点的可见性取决于屏幕上的像素数。

如果不让某些数据点共享相同的像素列或对数据进行下采样,则不能显示比像素数量更多的数据点。

您有 3 个选择:

  1. 使 X 轴可滚动并将 ScrollView 的 contentSize 宽度设置为 数量数据点。

  2. 保持 X 轴宽度固定,对数据进行下采样以减少 要显示的数据点,然后绘制有关的图表 下采样数据。

  3. 什么都不做,尝试在固定宽度内绘制所有数据点, 如果你的计算是正确的,一些数据点会重叠并且 在图表中共享相同的像素列。

第三个选项的解释编辑:

要在 200 像素宽的 X 轴上显示 1000 个数据点,每个像素将有 5 个数据点。所以;

数据点 0、1、2、3 和 4 将绘制在第一个像素列上。

数据点 5、6、7、8 和 9 将绘制在第二个像素列上。

数据点 10、11、12、13 和 14 将绘制在第 3 个像素列上。

等等。

对于您的示例,有 400 个像素和 1000 个数据点,这意味着每个像素有 2.5 个数据点。所以;

数据点 0、1、2 将绘制在第一个像素列上。

数据点 3、4 将绘制在第二个像素列上。

数据点 5、6、7 将绘制在第 3 个像素列上。

数据点 8、9 将绘制在第 4 个像素列上。

然后就这样继续下去。

关于xcode - 使用 1000 多个数据点在 Swift 中绘制折线图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27942773/

相关文章:

ios - NS无效参数异常 : +[NSBundle fyb_appTransportSecuritySettings]: unrecognized selector sent to class 0x3bd0c3c0

mysql - 从 mac 卸载 mysql 不工作

ios - 如何将日期绘制为 X 轴 (Swift)

javascript - iOS 视频在线播放并不总是在 swift 应用程序中在线播放

swift - 限制swift中的字符数

ios - Realm:为数据库名称创建全局配置

ios - 创建精简版,使用多个目标,如何避免覆盖完整版?

swift - UITableView 单元格延迟扩展

java - 在 Eclipse 中启动程序与在终端中启动程序有何不同?

css - 在 OS X 中使用 USB 鼠标与无线/触控板时滚动条的外观不同