Подтвердить что ты не робот

Как создать маркер плавающего графа с ios-chart

Я использую структуру ios-charts и хочу создать маркер, который плавает над графиком, когда я касаюсь и перемещаю палец из стороны в сторону. Я использую линейную диаграмму только для справки.

Однако я не могу понять, как получить позицию маркера на диаграмме, когда я прикоснусь к ней.

Я читал о подклассе MarkerView, но это не работает. Можете ли вы показать мне, как получить позицию точки, которая появляется, когда вы касаетесь ios-диаграммы?

4b9b3361

Ответ 1

Итак, я наконец получил это, чтобы работать, и хотел добавить его в сообщество. Вот как выглядит моя диаграмма:

введите описание изображения здесь

Когда вы проводите пальцем по графику, читатель выше перемещается и считывает значение из диаграммы.

Чтобы это получилось, я должен был сделать следующее:

  • В файле, который вы реализуете граф, обязательно включите ChartViewDelegate

  • Затем реализуем метод chartValueSelected.

  • Если вы затем используете метод getMarkerPosition, вы сможете центрировать свой "маркер" там, где вы хотите.

Вот пример кода:

class MarkerView: UIView {
    @IBOutlet var valueLabel: UILabel!
    @IBOutlet var metricLabel: UILabel!
    @IBOutlet var dateLabel: UILabel!
}

let markerView = MarkerView()

func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, dataSetIndex: Int, highlight: ChartHighlight) { 

    let graphPoint = chartView.getMarkerPosition(entry: entry,  highlight: highlight)

    // Adding top marker
    markerView.valueLabel.text = "\(entry.value)"
    markerView.dateLabel.text = "\(months[entry.xIndex])"
    markerView.center = CGPointMake(graphPoint.x, markerView.center.y)
    markerView.hidden = false

}

markerView - это xib, который я добавил вручную в основное представление, которое также содержит графическое представление. markerView - это UIView, содержащий три метки. Это 3,0, впечатления и Апр, которые вы видите на картинке.

graphPoint - это CGPoint, расположенный на графике. Вы можете использовать x и y для graphPoint, чтобы переместить ваш markerView. Здесь я просто сохранил значение y markerView и изменил его значение x, чтобы заставить его перемещаться вперед и назад при касании.

Ответ 2

Это основано на примере BallonMarker, представленном в репозитории iOS-Charts.

Надеюсь, это кому-нибудь пригодится, так как я не смог найти другие примеры подклассов MarkerImage так что это было много ошибок и ошибок для меня, так как никогда раньше не использовал CGContext

enter image description here

Чтобы использовать добавить этот класс

class PillMarker: MarkerImage {

    private (set) var color: UIColor
    private (set) var font: UIFont
    private (set) var textColor: UIColor
    private var labelText: String = ""
    private var attrs: [NSAttributedString.Key: AnyObject]!

    static let formatter: DateComponentsFormatter = {
        let f = DateComponentsFormatter()
        f.allowedUnits = [.minute, .second]
        f.unitsStyle = .short
        return f
    }()

    init(color: UIColor, font: UIFont, textColor: UIColor) {
        self.color = color
        self.font = font
        self.textColor = textColor

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        attrs = [.font: font, .paragraphStyle: paragraphStyle, .foregroundColor: textColor, .baselineOffset: NSNumber(value: -4)]
        super.init()
    }

    override func draw(context: CGContext, point: CGPoint) {
        // custom padding around text
        let labelWidth = labelText.size(withAttributes: attrs).width + 10
        // if you modify labelHeigh you will have to tweak baselineOffset in attrs
        let labelHeight = labelText.size(withAttributes: attrs).height + 4

        // place pill above the marker, centered along x
        var rectangle = CGRect(x: point.x, y: point.y, width: labelWidth, height: labelHeight)
        rectangle.origin.x -= rectangle.width / 2.0
        let spacing: CGFloat = 20
        rectangle.origin.y -= rectangle.height + spacing

        // rounded rect
        let clipPath = UIBezierPath(roundedRect: rectangle, cornerRadius: 6.0).cgPath
        context.addPath(clipPath)
        context.setFillColor(UIColor.white.cgColor)
        context.setStrokeColor(UIColor.black.cgColor)
        context.closePath()
        context.drawPath(using: .fillStroke)

        // add the text
        labelText.draw(with: rectangle, options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
    }

    override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
        labelText = customString(entry.y)
    }

    private func customString(_ value: Double) -> String {
        let formattedString = PillMarker.formatter.string(from: TimeInterval(value))!
        // using this to convert the left axis values formatting, ie 2 min
        return "\(formattedString)"
    }
}

Затем активируйте для своего графика

let marker = PillMarker(color: .white, font: UIFont.boldSystemFont(ofSize: 14), textColor: .black)
chartView.marker = marker