How to create a floating graph marker with ios-charts

前端 未结 2 1137
星月不相逢
星月不相逢 2021-01-31 05:59

I\'m using the ios-charts framework and want to create a marker that floats over the graph when I touch and move my finger from side to side. I\'m using a line chart just for r

2条回答
  •  梦毁少年i
    2021-01-31 06:49

    This is based on the example BallonMarker provided at the iOS-Charts repo.

    Hopefully this comes in handy for someone, as I couldn't find other subclass examples of MarkerImage so this was a lot of trail and error for me as never used CGContext before

    To use add this class

    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)"
        }
    }
    

    Then activate for your chart

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

提交回复
热议问题