Skip to content

Instantly share code, notes, and snippets.

@csr
Created June 27, 2017 08:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save csr/b107bb8ff0bceeb6223afdb4f34cdae2 to your computer and use it in GitHub Desktop.
Save csr/b107bb8ff0bceeb6223afdb4f34cdae2 to your computer and use it in GitHub Desktop.
Version 1.1
import UIKit
import SwiftCharts
// NOTE: you may have to set the module in the storyboard to "SwiftCharts", otherwise the view may not be recognized correctly, which leads to axis, labels and guidelines not showing
class AnalysisController: BaseViewController {
let monthData: [Int: [String: Float]] = [0: ["Jan": 20],
1: ["Feb": 4],
2: ["Mar": 20],
3: ["Apr": 83],
4: ["May": 750],
5: ["Jun": 600],
6: ["Jul": 300],
7: ["Aug": 49],
8: ["Sep": 400],
9: ["Oct": 49],
10: ["Nov": 39],
11: ["Dec": 1200]
]
private var chart: Chart?
let backgroundView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.masksToBounds = false
view.layer.shadowOpacity = 0.23
view.layer.shadowColor = UIColor(hex: "B1B2B3").cgColor
view.layer.shadowRadius = 4 // blur
view.layer.shadowOffset = CGSize(width: 0, height: 2) // Spread
return view
}()
let monthlyTotalView: MonthlySpendingView = {
let view = MonthlySpendingView()
return view
}()
fileprivate var chartView: ChartBaseView = {
let view = ChartBaseView()
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
//let currencyTextField = TSCurrencyTextField()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
rotated()
rotated()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.initChart()
self.setupMonthlySpendingView()
}
private func getMonthData() -> [MonthData] {
var items = [MonthData]()
for (index, data) in monthData {
for (monthName, expenses) in data {
let monthData = MonthData(index: index, monthName: monthName, expenses: expenses)
items.append(monthData)
}
}
return items.sorted(by: {$0.index < $1.index})
}
private func initChart() {
self.setupChartPosition()
// map model data to chart points
let xLabelSettings = ChartLabelSettings(font: ExamplesDefaults.labelFont, fontColor: ExamplesDefaults.labelTextColor, rotation: 0, rotationKeep: .top, shiftXOnRotation: false, textAlignment: .default)
let yLabelSettings = ChartLabelSettings(font: ExamplesDefaults.semiBoldFont, fontColor: ExamplesDefaults.labelTextColor, rotation: 0, rotationKeep: .center, shiftXOnRotation: false, textAlignment: .default)
let chartPoints: [ChartPoint] = getMonthData().enumerated().map {index, item in
let x = ChartAxisValueString(item.monthName, order: index, labelSettings: xLabelSettings)
//self.currencyTextField.amount = NSNumber(value: item.expenses)
let text = "$\(item.expenses)"
let y = ChartAxisValueString(text, order: Int(item.expenses), labelSettings: yLabelSettings)
return ChartPoint(x: x, y: y)
}
let labelSettings = ChartLabelSettings(font: ExamplesDefaults.labelFont, fontColor: ExamplesDefaults.labelTextColor, rotation: 0, rotationKeep: .center, shiftXOnRotation: false, textAlignment: .default)
// define x and y axis values (quick-demo way, see other examples for generation based on chartpoints)
let xValues = getMonthData().enumerated().map {index, item -> ChartAxisValueString in
return ChartAxisValueString(item.monthName, order: index, labelSettings: labelSettings)
}
let yValues = stride(from: 0, through: 10000, by: 200).map { (integer) -> ChartAxisValueString in
return ChartAxisValueString("$\(integer)", order: integer, labelSettings: labelSettings)
}
// create axis
//with axis values and axis title
let xModel = ChartAxisModel(axisValues: xValues, lineColor: .clear, axisTitleLabel: ChartAxisLabel(text: "", settings: labelSettings))
let yModel = ChartAxisModel(axisValues: yValues, lineColor: .clear, axisTitleLabel: ChartAxisLabel(text: "", settings: labelSettings.defaultVertical()))
let chartFrame = self.chartView.frame
// generate axes layers and calculate chart inner frame, based on the axis models
let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: ExamplesDefaults.chartSettings, chartFrame: chartFrame, xModel: xModel, yModel: yModel)
let (xAxis, yAxis, innerFrame) = (coordsSpace.xAxisLayer, coordsSpace.yAxisLayer, coordsSpace.chartInnerFrame)
// create layer with guidelines
let guidelinesLayerSettings = ChartGuideLinesLayerSettings(linesColor: ExamplesDefaults.guidelinesColor, linesWidth: ExamplesDefaults.guidelinesWidth)
let guidelinesLayer = ChartGuideLinesLayer(xAxisLayer: xAxis, yAxisLayer: yAxis, settings: guidelinesLayerSettings)
// view generator - this is a function that creates a view for each chartpoint
let barViewGenerator = {(chartPointModel: ChartPointLayerModel, layer: ChartPointsViewsLayer, chart: Chart) -> UIView? in
let bottomLeft = layer.modelLocToScreenLoc(x: 0, y: 0)
let barWidth: CGFloat = Env.iPad ? 60 : 43
let settings = ChartBarViewSettings(animDuration: 0.5)
let (p1, p2): (CGPoint, CGPoint) = {
return (CGPoint(x: chartPointModel.screenLoc.x, y: bottomLeft.y), CGPoint(x: chartPointModel.screenLoc.x, y: chartPointModel.screenLoc.y))
}()
let viewBar = ChartPointViewBar(p1: p1, p2: p2, width: barWidth, bgColor: #colorLiteral(red: 0.1369751394, green: 0.6553974748, blue: 1, alpha: 1), settings: settings)
return viewBar
}
// create layer that uses viewGenerator to display chartpoints
let chartPointsLayer = ChartPointsViewsLayer(xAxis: xAxis.axis, yAxis: yAxis.axis, chartPoints: chartPoints, viewGenerator: barViewGenerator)
let chartSettings = ExamplesDefaults.chartSettingsWithPanZoom
// create chart instance with frame and layers
let chart = Chart(view: self.chartView, innerFrame: innerFrame, settings: chartSettings, layers: [
coordsSpace.xAxisLayer,
coordsSpace.yAxisLayer,
guidelinesLayer,
chartPointsLayer
])
self.chart = chart
}
func rotated() {
for view in self.chartView.subviews {
view.removeFromSuperview()
}
self.initChart()
}
}
// MARK: - Actions
extension AnalysisController {
internal func updateMonthlyCost() {
APIService.sharedInstance.userMonthlySpendings { (cost) in
self.monthlyTotalView.setCostLabelValue(cost: cost)
}
}
}
// MARK: - Setup
extension AnalysisController {
internal func setupChartPosition() {
self.view.addSubview(self.backgroundView)
self.backgroundView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: -5).isActive = true
self.backgroundView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
self.backgroundView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.backgroundView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.74).isActive = true
self.backgroundView.addSubview(self.chartView)
self.chartView.topAnchor.constraint(equalTo: self.backgroundView.topAnchor).isActive = true //10
self.chartView.bottomAnchor.constraint(equalTo: self.backgroundView.bottomAnchor).isActive = true
self.chartView.widthAnchor.constraint(equalTo: self.backgroundView.widthAnchor, multiplier: 1).isActive = true // 1
self.chartView.centerXAnchor.constraint(equalTo: self.backgroundView.centerXAnchor, constant: -20).isActive = true //-20
}
internal func setupMonthlySpendingView() {
self.view.addSubview(self.monthlyTotalView)
self.monthlyTotalView.topAnchor.constraint(equalTo: self.backgroundView.bottomAnchor, constant: 15).isActive = true
self.monthlyTotalView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -7).isActive = true
self.monthlyTotalView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 7).isActive = true
self.monthlyTotalView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -60).isActive = true
self.updateMonthlyCost()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment