ios charts的部分探究

前言

之前就听过charts这个流行的图表库,而现在工程中要运用到这个第三方库。库中定义的属性还是挺多,对它的运用着实让我头大了几天。再加上是用swift写的,有点难理解。
自己在网上也查过,觉得这二篇文章对自己图表的运用帮助挺大的。
iOS源码解读-Charts图表1:了解基类(ChartViewBase、AxisBase(这篇让我对里面的属性有了个大致的理解)
ChartsUnderstandAndUsage(这个的用法比较清晰,便于运用)

探究

为了知道图表的绘制过程,自己单步运行查看。先摸索柱状图的原理


Simulator Screen Shot - iPhone 7 Plus - 2019-05-21 at 17.28.02.png

一般运用的话就是4步走:


屏幕快照 2019-05-21 下午5.11.22.png
   //添加柱状图
    func addBarChartView(){
        barChartView.backgroundColor = ZHFColor.white
        barChartView.frame.size = CGSize.init(width: ScreenWidth - 20, height: 300)
        barChartView.center = self.view.center
        barChartView.delegate = self
        self.view.addSubview(barChartView)
        //刷新按钮响应
        refreshrBtn.addTarget(self, action: #selector(updataData), for: UIControlEvents.touchUpInside)
    }
    
    func setBarChartViewBaseStyle(){
        //基本样式
        barChartView.noDataText = "暂无数据"//没有数据时的显示
        barChartView.drawValueAboveBarEnabled = true//数值显示是否在条柱上面
        barChartView.drawBarShadowEnabled = false//是否绘制阴影背景
        
        //交互设置 (把煮食逐个取消试试)
//        barChartView.scaleXEnabled = false//是否X轴缩放,拖动图表时x轴上的值不会变
        barChartView.scaleYEnabled = false //是否Y轴缩放
        barChartView.doubleTapToZoomEnabled = true//是否双击是否缩放
//        barChartView.pinchZoomEnabled = false//取消XY轴是否同时缩放
        barChartView.dragEnabled = true //是否启用拖拽图表
        barChartView.dragDecelerationEnabled = true //拖拽后是否有惯性效果
        barChartView.dragDecelerationFrictionCoef = 0.9 //拖拽后惯性效果的摩擦系数(0~1),数值越小,惯性越不明显
    }
    func setBarChartViewXY(){
        //1.X轴样式设置(对应界面显示的--->0月到7月)
        let xAxis: XAxis = barChartView.xAxis
        xAxis.valueFormatter = self //重写代理方法  设置x轴数据
        xAxis.axisLineWidth = 1 //设置X轴线宽
        xAxis.labelPosition = XAxis.LabelPosition.bottom //X轴(5种位置显示,根据需求进行设置)
        xAxis.drawGridLinesEnabled = true//不绘制网格
        xAxis.axisLineColor = UIColor.red //x轴颜色
        xAxis.labelWidth = 1 //设置label间隔,若设置为1,则如果能全部显示,则每个柱形下面都会显示label
        xAxis.labelFont = UIFont.systemFont(ofSize: 10)//x轴数值字体大小
        xAxis.labelTextColor = ZHFColor.brown//数值字体颜色
        xAxis.gridLineWidth = 1.0 //网格线
        xAxis.gridColor = UIColor.orange //网络线颜色
        xAxis.labelRotationAngle = 45 //旋转角度
    
        //2.Y轴左样式设置(对应界面显示的--->0 到 100)
        let leftAxisFormatter = NumberFormatter()
        leftAxisFormatter.minimumFractionDigits = 0
        leftAxisFormatter.maximumFractionDigits = 1
        leftAxisFormatter.positiveSuffix = " $"  //数字前缀positivePrefix、 后缀positiveSuffix
        let leftAxis: YAxis = barChartView.leftAxis
        leftAxis.valueFormatter = DefaultAxisValueFormatter.init(formatter: leftAxisFormatter)
        leftAxis.axisMinimum = 0     //最小值
//        leftAxis.axisMaximum = axisMaximum   //最大值
        leftAxis.forceLabelsEnabled = true //不强制绘制制定数量的label
        leftAxis.labelCount = 6    //Y轴label数量,数值不一定,如果forceLabelsEnabled等于true, 则强制绘制制定数量的label, 但是可能不平均
        leftAxis.inverted = false   //是否将Y轴进行上下翻转
        leftAxis.axisLineWidth = 0.5   //Y轴线宽
        leftAxis.axisLineColor = UIColor.red   //Y轴颜色
        leftAxis.labelPosition = YAxis.LabelPosition.outsideChart//坐标数值的位置
        leftAxis.labelTextColor = ZHFColor.brown//坐标数值字体颜色
        leftAxis.labelFont = UIFont.systemFont(ofSize: 10) //y轴字体大小
        //设置虚线样式的网格线(对应的是每条横着的虚线[10.0, 3.0]对应实线和虚线的长度)
        leftAxis.drawGridLinesEnabled = true //是否绘制网格线(默认为true)
        leftAxis.gridLineDashLengths = [10.0, 3.0] //线段类型
        leftAxis.gridColor = UIColor.purple //网格线颜色
        leftAxis.gridAntialiasEnabled = true//开启抗锯齿
        leftAxis.spaceTop = 0.15//最大值到顶部的范围比
        
        
        //设置限制线
        let limitLine : ChartLimitLine = ChartLimitLine.init(limit: Double(axisMaximum * 0.85), label: "限制线")
        limitLine.lineWidth = 2
        limitLine.lineColor = ZHFColor.green
        limitLine.lineDashLengths = [5.0, 2.0]
        limitLine.labelPosition = ChartLimitLine.LabelPosition.rightTop//位置
        limitLine.valueTextColor = ZHFColor.zhf66_contentTextColor
        limitLine.valueFont = UIFont.systemFont(ofSize: 12)
        leftAxis.addLimitLine(limitLine)
        leftAxis.drawLimitLinesBehindDataEnabled  = false //设置限制线在柱线图后面(默认在前)
        
        //3.Y轴右样式设置(如若设置可参考左样式)
        barChartView.rightAxis.enabled = false //不绘制右边轴线
        let rightAxis: YAxis = barChartView.rightAxis
        rightAxis.gridColor = UIColor.blue
        rightAxis.gridLineWidth = 1.0
        rightAxis.valueFormatter = DefaultAxisValueFormatter.init(formatter: leftAxisFormatter)
        rightAxis.axisMinimum = 0     //最小值
//        rightAxis.axisMaximum = 100   //最大值
        rightAxis.forceLabelsEnabled = true //不强制绘制制定数量的label
        rightAxis.labelCount = 6
        
        //4.描述文字设置
        barChartView.chartDescription?.text = "柱形图"//右下角的description文字样式 不设置的话会有默认数据
        barChartView.chartDescription?.position = CGPoint.init(x: 80, y: 5)//位置(及在barChartView的中心点)
        barChartView.chartDescription?.font = UIFont.systemFont(ofSize: 12)//大小
        barChartView.chartDescription?.textColor = ZHFColor.orange
        
        //5.设置类型试图的对齐方式,右上角 (默认左下角)
        let legend = barChartView.legend
        legend.enabled = true
        legend.horizontalAlignment = .right
        legend.verticalAlignment = .top
        legend.orientation = .horizontal
        legend.textColor = ZHFColor.orange
        legend.font = UIFont.systemFont(ofSize: 11.0)
    }
    //设置数据
    @objc func updataData(){
        //对应x轴上面需要显示的数据
        let count = 1
        let x1Vals: NSMutableArray  = NSMutableArray.init()
        for i in 0 ..< count {
            //x轴字体展示
            x1Vals.add("\(i)月")
            self.xVals = x1Vals
        }
         //对应Y轴上面需要显示的数据
        let yVals: NSMutableArray  = NSMutableArray.init()
        let arr:[Int] = [5,3,7]
        for i in 0 ..< count {
//            let val: Double = Double(arc4random_uniform(UInt32(axisMaximum)))
            let val:Double = Double(arr[I])
            let entry:BarChartDataEntry  = BarChartDataEntry.init(x:  Double(i), y: Double(val))
            yVals.add(entry)
        }
         //创建BarChartDataSet对象,其中包含有Y轴数据信息,以及可以设置柱形样式
        let set1: BarChartDataSet = BarChartDataSet.init(values: yVals as? [ChartDataEntry], label: "信息")
        set1.barBorderWidth = 0.2 //边线宽
        set1.drawValuesEnabled = true //是否在柱形图上面显示数值
        set1.highlightEnabled = true //点击选中柱形图是否有高亮效果,(单击空白处取消选中)
        set1.drawIconsEnabled = true
        
//    set1.setColors(ZHFColor.gray,ZHFColor.green,ZHFColor.yellow,ZHFColor.zhf_randomColor(),ZHFColor.zhf_randomColor())//设置柱形图颜色(是一个循环,例如:你设置5个颜色,你设置8个柱形,后三个对应的颜色是该设置中的前三个,依次类推)
      //  set1.setColors(ChartColorTemplates.material(), alpha: 1)
        set1.setColor(UIColor.red)//颜色一致
        let dataSets: NSMutableArray  = NSMutableArray.init()
        dataSets.add(set1)
     
        //创建BarChartData对象, 此对象就是barChartView需要最终数据对象
        let data:  BarChartData = BarChartData.init(dataSets: dataSets as? [IChartDataSet])
        data.barWidth = 0.5 //默认是0.85  (介于0-1之间)
        data.setValueFont(UIFont.systemFont(ofSize: 10))
        data.setValueTextColor(ZHFColor.orange)
        print("\(data.xMax) \(data.xMin) \(data.yMax) \(data.yMin)")
       
        let formatter: NumberFormatter = NumberFormatter.init()
        formatter.numberStyle = NumberFormatter.Style.currency//自定义数据显示格式  小数点形式(可以尝试不同看效果)
        let forma :DefaultValueFormatter = DefaultValueFormatter.init(formatter: formatter)
        
        data.setValueFormatter(forma)
        barChartView.data = data
        barChartView.animate(yAxisDuration: 1)//展示方式xAxisDuration 和 yAxisDuration两种
       //  barChartView.animate(xAxisDuration: 2, yAxisDuration: 2)//展示方式xAxisDuration 和 yAxisDuration两种
    }
}
//MARK:-   
extension BarChartVC :ChartViewDelegate,IAxisValueFormatter {
    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        let xStr = self.xVals[Int(value)] as! String
        print("xvalue ====  \(xStr)")
        return xStr
    }
    //1.点击选中
    func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
        ZHFLog(message: "点击选中")
    }
    //2.没有选中
    func chartValueNothingSelected(_ chartView: ChartViewBase) {
         ZHFLog(message: "没有选中")
    }
    //3.捏合放大或缩小
    func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
        ZHFLog(message: "捏合放大或缩小")
    }
    //4.拖拽图表
    func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) {
        ZHFLog(message: "拖拽图表")
    }
}

ChartsUnderstandAndUsage demo中有详细的注释。

1.1红色柱子的绘制方法
前期通过各种属性来算位置,offset等。
在BarChartRenderer中有drawData方法再调用drawDataSet

    open override func drawData(context: CGContext)
    {
        guard
            let dataProvider = dataProvider,
            let barData = dataProvider.barData
            else { return }
        
        for i in 0 ..< barData.dataSetCount
        {
            guard let set = barData.getDataSetByIndex(i) else { continue }
            
            if set.isVisible
            {
                if !(set is IBarChartDataSet)
                {
                    fatalError("Datasets for BarChartRenderer must conform to IBarChartDataset")
                }
                
                drawDataSet(context: context, dataSet: set as! IBarChartDataSet, index: i)
            }
        }
    }

在drawdataSet方法,画柱子的方法,经过buffer的操作rect在它的rects数组中,用 context.fill(barRect)就可以绘出红色的柱子了

屏幕快照 2019-05-21 下午6.19.00.png

这里只分析XAxisRenderer.swift,也就是X轴的绘制过程,x轴为什么会出现0等。
barChartView.data = data后,在设置方法中调用 notifyDataSetChanged()

  /// The data for the chart
    open var data: ChartData?
    {
        get
        {
            return _data
        }
        set
        {
            _data = newValue
            _offsetsCalculated = false
            
            guard let _data = _data else
            {
                setNeedsDisplay()
                return
            }
            
            // calculate how many digits are needed
            setupDefaultFormatter(min: _data.getYMin(), max: _data.getYMax())
            
            for set in _data.dataSets
            {
                if set.needsFormatter || set.valueFormatter === _defaultValueFormatter
                {
                    set.valueFormatter = _defaultValueFormatter
                }
            }
            
            // let the chart know there is new data
            notifyDataSetChanged()
        }
    }

再调用

 open override func notifyDataSetChanged()
    {
        renderer?.initBuffers()
        
        calcMinMax()  //算出数据中的最大值,最小值包括x轴,y轴
        
        leftYAxisRenderer.computeAxis(min: leftAxis._axisMinimum, max: leftAxis._axisMaximum, inverted: leftAxis.isInverted)
        rightYAxisRenderer.computeAxis(min: rightAxis._axisMinimum, max: rightAxis._axisMaximum, inverted: rightAxis.isInverted)
        
        if let data = _data
        {
            xAxisRenderer.computeAxis(
                min: _xAxis._axisMinimum,
                max: _xAxis._axisMaximum,
                inverted: false)

            if _legend !== nil
            {
                legendRenderer?.computeLegend(data: data)
            }
        }
        
        calculateOffsets()
        
        setNeedsDisplay()
    }

总结

charts画图表到是挺方便的,但如果是要修改UI话,源码又太难改,复杂的位置计算。

你可能感兴趣的:(ios charts的部分探究)