【问题标题】:Making a very simple graph with uibezierpath使用 uibezierpath 制作一个非常简单的图形
【发布时间】:2017-06-09 17:02:32
【问题描述】:

我的问题是

我想创建一个具有特定值的简单折线图。这是在mainviewcontroller 内的视图中完成的。我创建了一个名为图表的 UIview。当从 API 检索数据时,我将数据传递给图表。我想出了如何绘制轴,但我现在卡住了。我在谷歌上找不到任何关于如何设置间隔标签并使点动态显示的信息。

  • 绘制 xasis 及其标签。
  • 在图中画点。

我的问候

  • 我想出了如何去做我要求的所有事情。

我现在的代码:

class ChartView: UIView {

//some variables
var times: [String] = []
var AmountOfRain: [Double] = []
let pathy = UIBezierPath()
let pathx = UIBezierPath()
var beginwitharray = Array<CGFloat>()

// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
    // Drawing code

    //draw the y line
    pathy.move(to: CGPoint(x: 30, y: 10))
    pathy.addLine(to: CGPoint(x: 30, y: 10))
    pathy.addLine(to: CGPoint(x: 30, y: frame.size.height - 30))
    UIColor.black.setStroke()
    pathy.lineWidth = 1.0
    pathy.stroke()

    //draw the x line
    pathx.move(to: CGPoint(x: 30, y: frame.size.height - 30))
    pathx.addLine(to: CGPoint(x: 30, y: frame.size.height - 30))
    pathx.addLine(to: CGPoint(x: frame.size.width - 30, y: frame.size.height - 30))
    UIColor.black.setStroke()
    pathx.lineWidth = 1.0
    pathx.stroke()

    //when the data arrives form the SUPER slow duienradar API refresh it with the data
    if beginwitharray != []{
        //remove the label retriving data
        let label = viewWithTag(1)
        DispatchQueue.main.sync {
            label?.removeFromSuperview()
        }
        //create the dots in the graph
        var point = CGPoint()
        //simple way to do 2 loop in 1 loop.
        var intforbeginarray = 0
        let stoke = UIBezierPath()
        //get the first 6 itmes out of the rain array cuz of space issues
        let first6aumountarray = AmountOfRain[0...5]
        stoke.move(to: CGPoint(x: 30, y: self.frame.size.height - 30))

        //loop trough the data in the amounts array
        for amount in first6aumountarray{
            //determen the hight of the dot
            let InitialHeight = (CGFloat(amount) * (self.frame.size.height - 30))/6
            let pointHeight = (frame.size.height - 30) - InitialHeight

                //make the point so we can draw it using UIbezierpath()
                point = CGPoint(x: beginwitharray[intforbeginarray] + 20, y: pointHeight)
                intforbeginarray += 1

                //create the dot
                let dot = UIBezierPath()
                dot.addArc(withCenter: point, radius: CGFloat(5), startAngle: CGFloat(0), endAngle: CGFloat(360), clockwise: true)
                UIColor.black.setFill()
                dot.lineWidth = 30
                dot.fill()

                //create the line between dots will give a warning on the last one cuz the last one doenst go anyway
                stoke.addLine(to: point)
                stoke.move(to: point)
                stoke.lineWidth = 1
                UIColor.black.setStroke()
        }
        //make the strokes
        stoke.stroke()
    }
}
func getvalues(RainData: [Double], TimesData:[String]){

    //assing the data to the subview
    self.AmountOfRain = RainData
    self.times = TimesData

    //xaxis values
    let maxint = [0, 1, 2, 3, 4, 5, 6]

    //calculate the hight spacing to fit the graph
    let heightperstep = ((self.frame.size.height - 5)/6)-5
    var beginheight = self.frame.size.height - 35

    //calculate the width spacing to fit the graph
    let widthperstep = ((self.frame.size.width - 5)/6)-5
    var beginwith = CGFloat(30)

    //extra check to see if we have data at all.
    if times != []{
        //get the first 6 items out of the times array for use in our graph
        let first6 = times[0...5]
        //draw the label on the main queue
        DispatchQueue.main.sync {
            //draw the xaxis labels accroding to the spacing
            for number in maxint{
                let label = UILabel(frame: CGRect(x: 5, y: beginheight, width: 25, height: 15))
                label.text = "\(number)"
                self.addSubview(label)
                beginheight = beginheight - heightperstep
            }
            //draw the yaxis labels according to the spacing
            for time in first6{
                let label = UILabel(frame: CGRect(x: beginwith, y: self.frame.size.height - 20, width: 55, height: 15))
                label.text = time
                self.addSubview(label)
                beginwitharray.append(beginwith)
                beginwith = beginwith + widthperstep
            }
        }
    }
    //redrawthe graph with new data.
    setNeedsDisplay()
}}

任何帮助将不胜感激。我也不能使用 lib 或 pod,因为这是一个学校项目,我需要创建一个简单的图表。

编辑:

完成了我的代码,在运行此代码时清除了一个错误

我首先做的是绘制 x 轴和 y 轴。在此之后,我考虑了 aumountofrain 数据的合理值。事实证明,这实际上不能高于 6。因为我可以在空间中放置大约 6 个标签,所以我可以轻松地降低 1 直到达到 0。我所做的计算是针对我的特定框架高度的。在我弄清楚这一切和y轴的填充之后。这是一个弄清楚如何将点放在正确位置的问题。由于我已经在 beginwitharray 中有数据,我只需要计算高度。然后它只是循环遍历数据并绘制每个点。然后我只需要使用 uibezierpath 连接这些点。

我希望我的麻烦能在别人阅读我的做法时为他们节省很多时间。

【问题讨论】:

    标签: ios swift graph uibezierpath


    【解决方案1】:

    这可能会有所帮助:Draw Graph curves with UIBezierPath

    本质上,您需要为您拥有的每个数据集了解 y 轴的值范围,并根据这些范围为每个值分配一个 CGFloat 值(在您的情况下,英寸雨量需要与某些 CGFloat 值)。假设你有你的集合amountOfRain = [0.1, 1.3, 1.5, 0.9, 0.1, 0],所以你的范围是var rangeY = amountOfRain.max() - amountOfRain.min()。现在让我们找出您的第一个数据点 0.1 应该在图表上的位置,方法是将英寸雨量转换为与您已经绘制的轴相对应的 CGFloat 值,这个等式只是基本代数:let y1 = (amountOfRain[0]/rangeY)*((frame.size.height-30) - 10) + 10 现在看起来像您的雨样是有规律的,所以也许let x1:CGFloat = 10 现在你可以在与 (x1,y1) 对应的 CGPoint 添加一个点或其他东西。如果您对所有数据点执行此操作,它将创建一个图表,其中最大值位于图表顶部,最小值位于底部。祝你好运!

    【讨论】:

    • 谢谢你,这帮了很多忙,但它不是完整的遮阳篷。我会将我的问题更新为更多的遮阳篷
    猜你喜欢
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2010-11-19
    • 2021-12-02
    • 2012-07-21
    • 2015-06-27
    • 2014-10-24
    相关资源
    最近更新 更多