What is it you do not succeed in doing ?
That's pretty easy to code it by yourself.
You subclass UIView (ChartView) and draw the graph:
- The colored quadrants
- the axes and grid lines
- then draw the points : dataPoints is set from the ViewController ; values must be scaled to have their coordinates between -1 and +1
You set the dataPoints from the calling viewController: either at viewWillLayout or in the action of a 'draw it!" button.
Data values must be scalld to be in[-1.0 ... +1.0] range
if minXValue and maxXValue are the min and max x-values of your points, scale each rawXValue with
let scaledXValue = -1.0 + 2.0 * (rawXValue - minXValue) / (maxXValue - minXValue)
- idem for Y axis
The class structure would be similar to this (just to give the idea):
import UIKit
struct DataPoint {
var pos: CGPoint // Must be in [-1.0...1.0] range
var label: String
}
class ChartView: UIView {
var dataPoints :[DataPoint]? // To be loaded in ViewController
override func draw(_ rect: CGRect) {
// Just for showing some data: initialize some data here ; this must be done in the ViewController
// y axis starts from top
let dataOne = DataPoint(pos: CGPoint(x: 0.4, y: 0.5), label: "QAT")
let dataTwo = DataPoint(pos: CGPoint(x: 0.9, y: -0.2), label: "SWE")
let dataThree = DataPoint(pos: CGPoint(x: 0.05, y: 0), label: "BEU")
dataPoints = [dataOne, dataTwo, dataThree]
// Drawing code
// Set general values
let margin : CGFloat = 5.0
let drawingArea = self.bounds.insetBy(dx: margin, dy: margin) // Keep some marging around quadrants
let fullWidth = drawingArea.width
let fullHeight = drawingArea.height
let innerMidWidth = fullWidth / 2.0
let innerMidHeight = fullHeight / 2.0
let midDrawX = margin + innerMidWidth
let midDrawY = margin + innerMidHeight
let drawLeftMost = margin
let drawRightMost = fullWidth + margin
let drawTopMost = margin
let drawBottomMost = fullHeight + margin
// Draw the quadrants background
// Take care to the orientation of y axis
let quadBottomLeft = CGRect(x: drawLeftMost, y: midDrawY, width: innerMidWidth, height: innerMidHeight)
let quadTopLeft = CGRect(x: drawLeftMost, y: drawTopMost, width: innerMidWidth, height: innerMidHeight)
let quadBottomRight = CGRect(x: midDrawX, y: midDrawY, width: innerMidWidth, height: innerMidHeight)
let quadTopRight = CGRect(x: midDrawX, y: drawTopMost, width: innerMidWidth, height: innerMidHeight)
var quadPath = UIBezierPath(rect: quadTopLeft)
UIColor.yellow.setFill()
quadPath.fill()
quadPath = UIBezierPath(rect: quadBottomLeft)
UIColor.lightGray.setFill()
quadPath.fill()
quadPath = UIBezierPath(rect: quadTopRight)
UIColor.lightGray.setFill()
quadPath.fill()
quadPath = UIBezierPath(rect: quadBottomRight)
UIColor.lightGray.setFill()
quadPath.fill()
// Draw horizontal grid lines:
for i in 1...4 { // Border frame draws later
let y = drawTopMost + CGFloat(i) * fullHeight / 5.0
let startPoint = CGPoint(x: drawLeftMost, y: y)
let destPoint = CGPoint(x: drawRightMost, y: y)
let aPath = UIBezierPath()
aPath.move(to: startPoint)
aPath.addLine(to: destPoint)
UIColor.red.setStroke()
aPath.stroke()
}
// Draw vertical grid lines
for j in 1...9 { // Border frame draws later
let x = drawLeftMost + CGFloat(j) * fullWidth / 10.0
let startPoint = CGPoint(x: x, y: drawTopMost)
let destPoint = CGPoint(x: x, y: drawBottomMost)
let aPath = UIBezierPath()
aPath.move(to: startPoint)
aPath.lineWidth = 0.5
aPath.addLine(to: destPoint)
UIColor.red.setStroke()
aPath.stroke()
}
// Draw frame and axis
let framePath = UIBezierPath(rect: drawingArea)
framePath.lineWidth = 2.0
UIColor.black.setStroke()
framePath.stroke()
let axisPath = UIBezierPath()
// x axis first, with the labels
axisPath.move(to: CGPoint(x: drawLeftMost, y: midDrawY))
axisPath.lineWidth = 2.0
axisPath.addLine(to: CGPoint(x: drawRightMost, y: midDrawY))
UIColor.black.setStroke()
axisPath.stroke()
for j in 0...10 {
var scalePoint = CGPoint.zero
scalePoint.x = -10 + CGFloat(j) * fullWidth / 10.0
scalePoint.y = midDrawY - fullHeight / 15.0
let value = (j - 5) * 20
let textToDraw = "\(value)%"
textToDraw.draw(at: scalePoint)
}
// y axis now
axisPath.move(to: CGPoint(x: midDrawX, y: drawTopMost))
axisPath.addLine(to: CGPoint(x: midDrawX, y: drawBottomMost))
axisPath.stroke()
for i in 0...5 {
var scalePoint = CGPoint.zero
scalePoint.x = midDrawX - 30
scalePoint.y = -4 + CGFloat(i) * fullHeight / 5.0
let value = (2*i - 5) * 20
let textToDraw = "\(value)%"
textToDraw.draw(at: scalePoint)
}
// Draw data points
if let dataPoints = dataPoints {
for dataPoint in dataPoints {
var drawPoint = CGPoint.zero
drawPoint.x = midDrawX + midDrawX * dataPoint.pos.x // pos.x is in [-1...+1] range
drawPoint.y = midDrawY + midDrawY * dataPoint.pos.y // pos.y is in [-1...+1] range ; y axis: -1.0 is top, 1.0 bottom
let dotRect = CGRect(x: drawPoint.x - 3, y: drawPoint.y - 3, width: 6.0, height: 6.0)
let dotPath = UIBezierPath(ovalIn: dotRect)
UIColor.red.setFill()
dotPath.fill()
let textToDraw = dataPoint.label
textToDraw.draw(at: drawPoint)
}
}
}