目的
Chartsでグラフを描画する際、X軸のグリッド線の表示をカスタマイズしたい。
ライブラリ
任意のxAxisRendererをセットして描画をカスタマイズ
BarLineChartViewBaseのxAxisRendererプロパティには以下のコメントが書かれています。
/// The X axis renderer. This is a read-write property so you can set your own custom renderer here.
/// **default**: An instance of XAxisRenderer
@objc open lazy var xAxisRenderer = XAxisRenderer(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer)
XAxisRendererクラスのrenderGridLinesファンクションがグリッド線表示を行う処理です。
これを継承したクラスでオーバーライドしてあげれば良いでしょう。
例えば偶数のときだけ表示したいというような場合とします。
イメージ
デフォルト | 偶数だけ | |
---|---|---|
→ |
カスタムクラスの作成
swift:CustomXAxisRender.swift
/// 呼び出し元で制御できるようプロトコルを作っておく
protocol CustomXAxisRenderDelegate {
func isRender(entry:Double) -> Bool
}
/// Optional化するためのエクステンション
extension CustomXAxisRenderDelegate {
func isRender(entry:Double) -> Bool{
return true
}
}
/// レンダラーのカスタムクラス
class CustomXAxisRender: XAxisRenderer {
var renderDelegate:CustomXAxisRenderDelegate?
override init(viewPortHandler: ViewPortHandler, xAxis: XAxis?, transformer: Transformer?) {
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer)
}
open override func renderGridLines(context: CGContext)
{
guard
let xAxis = self.axis as? XAxis,
let transformer = self.transformer
else { return }
if !xAxis.isDrawGridLinesEnabled || !xAxis.isEnabled
{
return
}
context.saveGState()
defer { context.restoreGState() }
context.clip(to: self.gridClippingRect)
context.setShouldAntialias(xAxis.gridAntialiasEnabled)
context.setStrokeColor(xAxis.gridColor.cgColor)
context.setLineWidth(xAxis.gridLineWidth)
context.setLineCap(xAxis.gridLineCap)
if xAxis.gridLineDashLengths != nil
{
context.setLineDash(phase: xAxis.gridLineDashPhase, lengths: xAxis.gridLineDashLengths)
}
else
{
context.setLineDash(phase: 0.0, lengths: [])
}
let valueToPixelMatrix = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
let entries = xAxis.entries
for i in stride(from: 0, to: entries.count, by: 1)
{
/// 元の処理からの変更点はここだけ
/// 引数にグラフメモリの値をセットしてあげる
if let delegate = self.renderDelegate {
/// entriesにグリッド線の値が入っている
if !delegate.isRender(entry:entries[i]) {
continue
}
}
position.x = CGFloat(entries[i])
position.y = position.x
position = position.applying(valueToPixelMatrix)
drawGridLine(context: context, x: position.x, y: position.y)
}
}
}
XAxisRendererクラスにデリゲートを追加し、その戻り値で描画有無を制御しているだけです。
これを使うViewControllerとしては
ViewController.swift
class ViewController: UIViewController,CustomXAxisRenderDelegate {
var chartView:LineChartView!
override func viewDidLoad() {
super.viewDidLoad()
self.makeChart()
}
private func makeChart() {
self.chartView = LineChartView(frame: self.view.frame)
/// カスタムレンダラーをインスタンス化。コンストラクタの値はChartViewや元のXAxisのを再利用
var customRender = CustomXAxisRender(viewPortHandler: self.chartView.viewPortHandler,
xAxis: self.chartView.xAxis,
transformer: self.chartView.xAxisRenderer.transformer!)
/// デリゲートをセット
customRender.renderDelegate = self
/// カスタムレンダラーをセットする
self.chartView.xAxisRenderer = customRender
let xAxis = self.chartView.xAxis
xAxis.labelPosition = .bottom
chartView.data = self.createChartsData()
self.view.addSubview(chartView)
}
/// チャートデータのセットなど
private func createChartsData() -> LineChartData {
let bellValues = [120,109,86,214,487,64,87]
let day = [1,2,3,4,5,6,7]
var datas:[ChartDataEntry] = []
for i in 0..<day.count {
datas.append(ChartDataEntry(x: Double(day[i]), y: Double(bellValues[i])))
}
var lineChart = LineChartDataSet(entries: datas)
return LineChartData(dataSets: [lineChart])
}
/// グリッド線描画毎に呼ばれるデリゲート
func isRender(entry:Double) -> Bool{
return Int(entry.truncatingRemainder(dividingBy: 2.0)) == 0
}
}