Swift - 第三方图表库Charts使用详解8(折线图7:事件响应、MarkerView标签)

七、事件响应、MarkerView 标签
1,ChartViewDelegate
ChartViewDelegate 提供了如下 4 种代理方法,方便我们与图表进行交互时进行一些响应操作:
chartValueSelected(chartView:, entry:, highlight:):拐点选中回调
chartValueNothingSelected(chartView:):拐点取消选中回调
chartScaled(chartView:, scaleX:, scaleY:):图表通过手势缩放后的回调
chartTranslated(chartView:, dX:, dY:):图表通过手势拖动后的回调

2,使用样例
(1)效果图
当我们点击选中某个拐点时,图表上会出现一个 MarkerView 标签显示当前拐点的值。
当拐点选中、取消选中,以及图表缩放、拖动时,控制台会输出相关的信息。
原文:Swift - 第三方图表库Charts使用详解8(折线图7:事件响应、MarkerView标签
)原文:Swift - 第三方图表库Charts使用详解8(折线图7:事件响应、MarkerView标签)

(2)样例代码
import UIKit
import Charts

class ViewController: UIViewController, ChartViewDelegate {

//折线图
var chartView: LineChartView!
 
override func viewDidLoad() {
    super.viewDidLoad()
     
    //创建折线图组件对象
    chartView = LineChartView()
    chartView.frame = CGRect(x: 20, y: 80, width: self.view.bounds.width - 40,
                             height: 270)
    chartView.delegate = self //设置代理
    self.view.addSubview(chartView)
     
    //生成10条随机数据
    var dataEntries = [ChartDataEntry]()
    for i in 0..<10 {
        let y = arc4random()%100
        let entry = ChartDataEntry.init(x: Double(i), y: Double(y))
        dataEntries.append(entry)
    }
    //这10条数据作为1根折线里的所有数据
    let chartDataSet = LineChartDataSet(values: dataEntries, label: "图例1")

    //目前折线图只包括1根折线
    let chartData = LineChartData(dataSets: [chartDataSet])
     
    //设置折线图数据
    chartView.data = chartData
}
 
//折线上的点选中回调
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry,
                        highlight: Highlight) {
    print("选中了一个数据")
    //显示该点的MarkerView标签
    self.showMarkerView(value: "\(entry.y)")
}
 
//显示MarkerView标签
func showMarkerView(value:String){
    let marker = MarkerView(frame: CGRect(x: 20, y: 20, width: 80, height: 20))
    marker.chartView = self.chartView
    let label = UILabel(frame: CGRect(x: 0, y: 0, width: 80, height: 20))
    label.text = "数据:\(value)"
    label.textColor = UIColor.white
    label.font = UIFont.systemFont(ofSize: 12)
    label.backgroundColor = UIColor.gray
    label.textAlignment = .center
    marker.addSubview(label)
    self.chartView.marker = marker
}
 
//折线上的点取消选中回调
func chartValueNothingSelected(_ chartView: ChartViewBase) {
    print("取消选中的数据")
}
 
//图表通过手势缩放后的回调
func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
    print("图表缩放了")
}
 
//图表通过手势拖动后的回调
func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) {
   print("图表移动了")
}

}

附一:气泡标签(BalloonMarker)
1,效果图
气泡标签(BalloonMarker)和上面普通标题(MarkerView)标签不同的是,它有个三角箭头指向对应的拐点,这样看起来更加直观些。
原文:Swift - 第三方图表库Charts使用详解8(折线图7:事件响应、MarkerView标签)

2,BalloonMarker.swift
默认情况下 Charts 框架里是不含气泡标签组件的,我们首先创建一个 BalloonMarker.swift,内容如下:
BalloonMarker.swift 代码是从 Charts 的 Demo 工程中复制出来的,我稍作修改:原先标签是自动显示对应的值,我将其注释掉,改成在外面手动赋值。

import Foundation
import Charts

open class BalloonMarker: MarkerImage
{
open var color: UIColor
open var arrowSize = CGSize(width: 15, height: 11)
open var font: UIFont
open var textColor: UIColor
open var insets: UIEdgeInsets
open var minimumSize = CGSize()

fileprivate var label: String?
fileprivate var _labelSize: CGSize = CGSize()
fileprivate var _paragraphStyle: NSMutableParagraphStyle?
fileprivate var _drawAttributes = [NSAttributedStringKey : AnyObject]()
 
public init(color: UIColor, font: UIFont, textColor: UIColor, insets: UIEdgeInsets)
{
    self.color = color
    self.font = font
    self.textColor = textColor
    self.insets = insets
     
    _paragraphStyle = NSParagraphStyle.default.mutableCopy()
        as? NSMutableParagraphStyle
    _paragraphStyle?.alignment = .center
    super.init()
}
 
open override func offsetForDrawing(atPoint point: CGPoint) -> CGPoint
{
    var offset = self.offset
    var size = self.size
     
    if size.width == 0.0 && image != nil
    {
        size.width = image!.size.width
    }
    if size.height == 0.0 && image != nil
    {
        size.height = image!.size.height
    }
     
    let width = size.width
    let height = size.height
    let padding: CGFloat = 8.0

    var origin = point
    origin.x -= width / 2
    origin.y -= height

    if origin.x + offset.x < 0.0
    {
        offset.x = -origin.x + padding
    }
    else if let chart = chartView,
        origin.x + width + offset.x > chart.bounds.size.width
    {
        offset.x = chart.bounds.size.width - origin.x - width - padding
    }
     
    if origin.y + offset.y < 0
    {
        offset.y = height + padding;
    }
    else if let chart = chartView,
        origin.y + height + offset.y > chart.bounds.size.height
    {
        offset.y = chart.bounds.size.height - origin.y - height - padding
    }
     
    return offset
}
 
open override func draw(context: CGContext, point: CGPoint)
{
    guard let label = label else { return }
     
    let offset = self.offsetForDrawing(atPoint: point)
    let size = self.size
     
    var rect = CGRect(
        origin: CGPoint(
            x: point.x + offset.x,
            y: point.y + offset.y),
        size: size)
    rect.origin.x -= size.width / 2.0
    rect.origin.y -= size.height
     
    context.saveGState()
     
    context.setFillColor(color.cgColor)

    if offset.y > 0
    {
        context.beginPath()
        context.move(to: CGPoint(
            x: rect.origin.x,
            y: rect.origin.y + arrowSize.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0,
            y: rect.origin.y + arrowSize.height))
        //arrow vertex
        context.addLine(to: CGPoint(
            x: point.x,
            y: point.y))
        context.addLine(to: CGPoint(
            x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0,
            y: rect.origin.y + arrowSize.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x + rect.size.width,
            y: rect.origin.y + arrowSize.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x + rect.size.width,
            y: rect.origin.y + rect.size.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x,
            y: rect.origin.y + rect.size.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x,
            y: rect.origin.y + arrowSize.height))
        context.fillPath()
    }
    else
    {
        context.beginPath()
        context.move(to: CGPoint(
            x: rect.origin.x,
            y: rect.origin.y))
        context.addLine(to: CGPoint(
            x: rect.origin.x + rect.size.width,
            y: rect.origin.y))
        context.addLine(to: CGPoint(
            x: rect.origin.x + rect.size.width,
            y: rect.origin.y + rect.size.height - arrowSize.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0,
            y: rect.origin.y + rect.size.height - arrowSize.height))
        //arrow vertex
        context.addLine(to: CGPoint(
            x: point.x,
            y: point.y))
        context.addLine(to: CGPoint(
            x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0,
            y: rect.origin.y + rect.size.height - arrowSize.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x,
            y: rect.origin.y + rect.size.height - arrowSize.height))
        context.addLine(to: CGPoint(
            x: rect.origin.x,
            y: rect.origin.y))
        context.fillPath()
    }

    if offset.y > 0 {
        rect.origin.y += self.insets.top + arrowSize.height
    } else {
        rect.origin.y += self.insets.top
    }

    rect.size.height -= self.insets.top + self.insets.bottom
     
    UIGraphicsPushContext(context)
     
    label.draw(in: rect, withAttributes: _drawAttributes)
     
    UIGraphicsPopContext()
     
    context.restoreGState()
}
 
/**
open override func refreshContent(entry: ChartDataEntry, highlight: Highlight)
{
    setLabel(String(entry.y))
}
 **/
 
open func setLabel(_ newLabel: String)
{
    label = newLabel
     
    _drawAttributes.removeAll()
    _drawAttributes[.font] = self.font
    _drawAttributes[.paragraphStyle] = _paragraphStyle
    _drawAttributes[.foregroundColor] = self.textColor
     
    _labelSize = label?.size(withAttributes: _drawAttributes) ?? CGSize.zero
     
    var size = CGSize()
    size.width = _labelSize.width + self.insets.left + self.insets.right
    size.height = _labelSize.height + self.insets.top + self.insets.bottom
    size.width = max(minimumSize.width, size.width)
    size.height = max(minimumSize.height, size.height)
    self.size = size
}

}

3,使用样例
使用时将之前的 showMarkerView 方法修改成如下即可:

//显示MarkerView标签
func showMarkerView(value:String){
//使用气泡状的标签
let marker = BalloonMarker(color: UIColor(white: 180/255, alpha: 1),
font: .systemFont(ofSize: 12),
textColor: .white,
insets: UIEdgeInsets(top: 8, left: 8, bottom: 20, right: 8))
marker.chartView = self.chartView
marker.minimumSize = CGSize(width: 80, height: 40)
marker.setLabel(“数据:(value)”)
self.chartView.marker = marker
}

附二:改变选中点的颜色
当选中某个拐点时,如果光有十字线可能还不够明显,我们可以把选中点的颜色和其它点做个区分:
原文:Swift - 第三方图表库Charts使用详解8(折线图7:事件响应、MarkerView标签)

具体的实现方法可以参考我之前写的这篇文章:
Swift - 第三方图表库Charts使用详解4(折线图3:选中点高亮、十字线样式)

原文出自:www.hangge.com 原文链接:https://www.hangge.com/blog/cache/detail_2125.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值