How to create a floating graph marker with ios-chart

I use the ios-charts structure and want to create a marker that floats above the chart when I touch and move my finger from side to side. I am using a line chart for reference only.

However, I cannot figure out how to get the marker position on the chart when I touch it.

I read about the MarkerView subclass, but this does not work. Can you show me how to get the position of the point that appears when you touch the ios diagram?

+10
ios swift ios-charts
source share
2 answers

So, I finally got it to work, and wanted to add it to the community. Here's what my chart looks like:

enter image description here

When you drag your finger along the graph, the reader above moves and reads the value from the diagram.

For this to work, I had to do the following:

  • In the file that you are implementing the graph, be sure to include ChartViewDelegate

  • Then we implement the chartValueSelected method.

  • If you then use the getMarkerPosition method, you can center your β€œmarker” wherever you want.

Here is a sample code:

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 is an xib that I manually added to the main view, which also contains a graphical view. markerView is a UIView containing three labels. These are 3.0, impressions and Apr, which you see in the picture.

graphPoint is a CGPoint located on a graph. You can use x and y for graphPoint to move your markerView . Here, I just saved the y value of the markerView and changed its x value to make it move forward and backward when touched.

+23
source share

This is based on the BallonMarker example provided in the iOS-Charts repository .

I hope this is useful to someone, since I could not find other examples of subclasses of MarkerImage so it was a lot of errors and errors for me, since I had never used CGContext

enter image description here

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 schedule

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

All Articles