[iOS] Charts 라이브러리를 이용해서 그래프 그리기

Youngwoo Lee·2022년 2월 22일
0

iOS

목록 보기
42/46
post-thumbnail

들어가며

암호화폐 관련 앱을 제작하면서, 주식 앱이나 암호화폐 거래소에서 쉽게 접할 수 있는 CandleStick Chart를 직접 구현하게 되었는데, 이를 기록으로 남겨두려고 해요.

Charts

iOS 에서 차트를 그릴 수 있는 라이브러리들을 여러 가지 도전해봤는데, Charts 라이브러리는 Swift-iOS로 제공되는 라이브러리로 가장 쉽고 코드가 깔끔했던 것 같아요.

먼저 그리고자 했던 차트는 BarChartCandleStickChart 였어요. 그럼 해당 View들을 살펴보도록 할게요.

BarChartView


import Foundation
import CoreGraphics

/// Chart that draws bars.
open class BarChartView: BarLineChartViewBase, BarChartDataProvider

해당 객체의 경우는 BarLineChartViewBase , BarChartDataProvider 를 상속 및 채택하는 객체에요

그럼 먼저 BarLineChartViewBase 부터 알아보도록 할게요


BarLineChartViewBase

/// Base-class of LineChart, BarChart, ScatterChart and CandleStickChart.
open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartDataProvider, NSUIGestureRecognizerDelegate
{
    private var _pinchZoomEnabled = false
    private var _doubleTapToZoomEnabled = true
    private var _dragXEnabled = true
    private var _dragYEnabled = true
    private var _scaleXEnabled = true
    private var _scaleYEnabled = true

BarLineChartViewBase 의 경우는 아래와 같이 X,Y 축을 통해서 차트를 그리는 것을 위한 정의가 되어 있어요

해당 객체의 프로퍼티들을 통해서 차트의 베이스가 되는 배경, 움직임 등을 수정할 수 있을 것 같네요

BarChartDataProvider

public protocol BarChartDataProvider: BarLineScatterCandleBubbleChartDataProvider
{
    var barData: BarChartData? { get }
    
    var isDrawBarShadowEnabled: Bool { get }
    var isDrawValueAboveBarEnabled: Bool { get }
    var isHighlightFullBarEnabled: Bool { get }
}

BarChart에서 하나의 Bar를 나타낼 때 필요한 Data 및 Bar의 UI 속성을 지정해주기 위한 속성 등을 제공하는 Protocol로 보이네요

BarLineScatterCandleBubbleChartDataProvider 를 상속하는 관계이며, 위에서 말한 것처럼 Provider를 붙이고 있는 모든 프로토콜들은 차트들의 데이터를 어떻게 제공할지를 설정할 수 있는 속성들을 가지고 있는 것 같아요.


BarChartView 그리기

그럼 여러 예시를 통해서 한 번 그려보도록 할게요. BarChartView의 경우는 간단하게 그려보죠

일단은 ChartView 의 속성부터 변경하도록 할게요

private func attribute() {
	self.noDataText = "데이터가 없습니다."
    self.noDataFont = .systemFont(ofSize: 20)
    self.noDataTextColor = .lightGray
    self.backgroundColor = .white
    self.xAxis.setLabelCount(4, force: false)
    self.xAxis.labelPosition = .bottom
    self.dragDecelerationEnabled = false
    self.autoScaleMinMaxEnabled = true
    self.doubleTapToZoomEnabled = false
    self.highlightPerTapEnabled = false
    self.rightAxis.enabled = false
    self.leftAxis.enabled = true
    self.scaleYEnabled = false
    self.dragYEnabled = false
}

네이밍이 직관적으로 되어 있어서 따로 설명은 하지 않아도 쉽게 알아볼 수 있을 것이라고 생각해요. 단순하게 View의 속성을 변경시키는 것이라 설명할 것이 없네요


private func setChart(chartData: [ChartData]) {
  let dataEntries = self.convertToDataEntries(from: chartData)
  let axisValues = self.convertToAxisValues(from: chartData)
  let colors = self.barColors(with: chartData)

  let chartDataSet = BarChartDataSet(entries: dataEntries).then {
    $0.colors = colors
    $0.drawValuesEnabled = false
    $0.highlightEnabled = false
  }
  
  let chartData = CandleChartData(dataSet: chartDataSet)
  self.data = chartData
  self.xAxis.valueFormatter = IndexAxisValueFormatter(values: axisValues)
  self.setVisibleXRangeMaximum(20.0)
  self.moveViewToX(self.chartXMax)
  self.drawMarkers = false
}

여기서부터는 조금씩 볼 내용이 있겠네요.

먼저, ChartData 의 경우는 Charts 라이브러리 내의 타입이 아니라 서버로부터 받아온 Entity를 Chart에서 사용하기 위해서 개인적으로 만든 모델 타입이라는 점!을 염두하시고 코드를 보면 좋겠네요.


BarChartView 에서 봉을 그리기 위해서는 우리는 먼저 BarChartDataEntry 가 있어야 해요. 그래서 아래처럼 ChartData 들을 통해서 Entry를 생성해줬어요

private func convertToDataEntries(from graphData: [ChartData]) -> [BarChartDataEntry] {
  return graphData.enumerated().map {
    BarChartDataEntry(x: Double($0),
                      y: $1.exchangeVolume)

  }
}

x값은 단순하게 Index 이며, y값은 체결량을 의미해요

그리고 x축 데이터의 의미를 알려주기 위해서 AxisValueString을 생성해볼 거에요

private func convertToAxisValues(from graphData: [ChartData]) -> [String] {
  return graphData.map { $0.dateText }
}

x값은 dateText 로 날짜를 가져왔어요

하지만, 이것만으로는 부족하죠. 각 Bar 들을 값을 통해서 어떤 정보인지 알 수 있지만 Bar 자체만으로도 정보를 담을 수 있기에 색을 넣어볼게요.

이 부분은 살짝 억지스러웠는데, 각 Bar 에 대한 색 정보를 모두 담아서 BarChartDataSet 에 넣어줬어요

private func barColors(with data: [ChartData]) -> [UIColor] {
  return data.map {
    if $0.openPrice > $0.closePrice {
      return .systemBlue
    } else if $0.openPrice < $0.closePrice {
      return .systemRed
    } else {
      return .systemRed
    }
  }
}

이렇게 작성할 경우, 위 같은 결과가 나와요


디테일 한 부분까지는 손대지 않았지만, 정리하면 깔끔한 차트가 나오겠네요.
다음 시간에는 CandleStickChart 를 그려보도록 할게요

profile
iOS Developer Student

0개의 댓글