之前一直都說要寫關于繪制折線和柱狀圖的相關文章,之前在忙新的項目,這幾天不忙,也是之前那篇文章有小伙伴問我折線與柱狀圖繪制的相關問題,說一些自己研究Charts的經驗,僅代表個人觀點,如有錯誤,請多指正,下面進入正題。
首先看一下目前折線圖的效果
這個效果是經歷了將近一個月的時間,為了有這樣的效果,我翻遍了簡書的文章,問了很多人,技術群,這個效果是在產品經理每周叨叨叨逼出來的,不要問我為什么這么說,真的是每天都追著我改改改,優化優化優化,所以現在就有了這樣的效果,下面是代碼,代碼里面該標注釋的地方都有注釋,不要問我有github鏈接么,所有代碼都在這里,試試就知道了,講真,我不騙人,畢竟試試又不會懷孕~~??
聲明一下繪制的LineChartView只有左Y軸,沒有右Y軸,右Y軸設置也很簡單,請參考左Y軸,但是一般只要左Y軸就好了。
首先是初始化,喜歡用懶加載初始化,因為頁面有好幾個圖表,第一時間不一定用得到折線圖,初始化只有一句話,是不是很爽,別想太多,因為好幾個模塊用到的東西都一樣,就放在一個工具類里面了,MBSChartTool這個工具類,有文章,全是代碼以及注釋。。。這個工具類只是為了偷懶,最后控制器還有遵守一個代理
@interface ViewController ()<ChartViewDelegate>
@property (nonatomic, strong) LineChartView *lineChartView;
@end
#pragma mark - getter and setter
- (LineChartView *)lineChartView
{
if (_lineChartView == nil) {
_lineChartView = [MBSChartTool lineChartViewForLeftWithDelegate:self];
}
return _lineChartView;
}
- (NSArray *)colorArray
{
if (_colorArray == nil) { //橘黃色 藍色 淡綠色 淺紫色 淺紅色
_colorArray = @[ RGB(242, 152, 80), RGB(92, 178, 240), RGB(158, 202, 97), RGB(219, 95, 153), RGB(233, 84, 83)];
}
return _colorArray;
}
- (NSArray *)xTitles
{
if (_xTitles == nil) {
_xTitles = @[@"第1周", @"第2周", @"第3周", @"第4周", @"第5周"];
}
return _xTitles;
}
添加LinechartView 與 設置LinechartData
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:self.lineChartView];
[self.lineChartView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self.view).insets(UIEdgeInsetsMake(10, 20, 10, 10));
}];
[self setData];
}
- (void)setData
{
NSArray *array = @[@"5553.8", @"5959.3", @"1961.7", @"<null>", @"<null>"];
NSArray *array1 = @[@"998.5", @"1014.5", @"249", @"<null>", @"<null>"];
NSMutableArray *valueArray = [NSMutableArray array];
[valueArray addObject:array];
[valueArray addObject:array1];
NSMutableArray *dataSets = [NSMutableArray array];
double leftAxisMin = 0;
double leftAxisMax = 0;
for (int i = 0; i < valueArray.count; i++) {
NSArray *values = valueArray[i];
NSMutableArray *yVals = [NSMutableArray array];
NSString *legendName = [NSString stringWithFormat:@"第%d個圖例", i];
for (int i = 0; i < values.count; i++)
{
NSString *valStr = [NSString stringWithFormat:@"%@", values[i]];
double val = [valStr doubleValue];
leftAxisMax = MAX(val, leftAxisMax);
leftAxisMin = MIN(val, leftAxisMax);
ChartDataEntry *entry = [[ChartDataEntry alloc] initWithX:i y:val];
[yVals addObject:entry];
}
LineChartDataSet *dataSet = [[LineChartDataSet alloc] initWithValues:yVals label:legendName];
dataSet.lineWidth = 3.0f;//折線寬度
dataSet.drawValuesEnabled = YES;//是否在拐點處顯示數據
dataSet.valueColors = @[self.colorArray[i]];//折線拐點處顯示數據的顏色
[dataSet setColor:self.colorArray[i]];//折線顏色
dataSet.drawSteppedEnabled = NO;//是否開啟繪制階梯樣式的折線圖
dataSet.drawCirclesEnabled = NO;//是否繪制拐點
dataSet.circleRadius = 3.0f;//拐點半徑
dataSet.axisDependency = AxisDependencyLeft;
dataSet.drawCircleHoleEnabled = YES;//是否繪制中間的空心
dataSet.circleHoleRadius = 1.0f;//空心的半徑
dataSet.circleHoleColor = self.colorArray[i];//空心的顏色
dataSet.highlightEnabled = YES;//選中拐點,是否開啟高亮效果(顯示十字線)
dataSet.highlightColor = [UIColor clearColor];
dataSet.valueFont = [UIFont systemFontOfSize:12];
[dataSets addObject:dataSet];
}
double leftDiff = leftAxisMax - leftAxisMin;
if (leftAxisMax == 0 && leftAxisMin == 0) {
leftAxisMax = 100.0;
leftAxisMin = -10.0;
} else {
leftAxisMax = (leftAxisMax + leftDiff * 0.2);
leftAxisMin = (leftAxisMin - leftDiff * 0.1);
}
self.lineChartView.leftAxis.axisMaximum = leftAxisMax;
self.lineChartView.leftAxis.axisMinimum = leftAxisMin;
LineChartData *data = [[LineChartData alloc] initWithDataSets:dataSets];
self.lineChartView.data = nil;
self.lineChartView.xAxis.axisMinimum = -0.8;
self.lineChartView.xAxis.axisMaximum = 5.1;
self.lineChartView.data = data;
[self.lineChartView animateWithXAxisDuration:0.3f];
}
x軸數據源方法
lineChartView.xAxis.valueFormatter = target;
這句話如果設置了,就必須實現x軸的數據源方法
- (NSString *)stringForValue:(double)value axis:(ChartAxisBase *)axis
{
return self.xTitles[(int)value % self.monthTitles.count];
}
xTitles就是你需要在x軸展現的標題數組,賦值就這么寫就好,別問為什么,英語好的點進去看看就知道了,四級過了英語就不看了。
這樣就會有出現下面的多系列折線圖
你看見x軸的標題多了一個,強迫癥受不了,產品經理看見也難受,所以要改正這個,其實這樣的圖表還是好的,看一下最初不知道設置零起點與x軸時的折線圖。
這樣的折線圖,看著更加讓人難受,這就是最初不知道方法不知道如何解決時的折線圖,但是我那時候想到一個曲線救國的方法,就是在xtitles最前面添加倆個空的字符串,在賦值的時候把i變成了i+2,這樣雖然不是很完美,但是基本解決零起點問題,也不至于讓產品天天盯著你改改改,后來自己決定這樣不是問題,就去看demo,找到了新的解決辦法,當初步解決的時候,高興的我那感覺真的無法形容,就是可以在產品問你改好了么時候,你可以得意看著他,說一句哥改好了。說正事,方法如下:
曲線救國方法(可以忽略):
ChartDataEntry *entry = [[ChartDataEntry alloc] initWithX:i + 2 y:val];
正確方法:
self.lineChartView.xAxis.axisMinimum = -0.8;
self.lineChartView.xAxis.axisMaximum = 5.1;
因為x標題數組較少,所有就這么寫了,標準的方法:
self.lineChartView.xAxis.axisMinimum = data.xMin - 0.8;
self.lineChartView.xAxis.axisMaximum = data.xMax + 0.8;
采用標準方法修復x軸最小值與最大值問題效果如之前不完美的折線圖
這樣雖然距離左右軸美觀了,但是有重復問題,我目前也沒有找到直接解決問題的辦法,但是可以采用方法折線圖的方法間接解決此問題,放大折線圖之后不讓進行縮放與拖動,如果你夠耐心的話,可以繼續調試ineChartView.xAxis.axisMaximum和lineChartView.xAxis.axisMinimum這倆個屬性,達到一個理想的狀態,方法折線圖方法如下:
[_lineChartView zoomWithScaleX:1.03 scaleY:1 x:0 y:0];
放大的方法有了,又會遇到新的問題,方法的比例是多少,這個好解決,折線圖有個代理方法,添加代理方法,手動進行縮放,打印里面的放大比例,然后把這個值填進去就是你需要的,不要問我為什么這么機智,逼出來的
#pragma mark - ChartView Delegate
- (void)chartScaled:(ChartViewBase *)chartView scaleX:(CGFloat)scaleX scaleY:(CGFloat)scaleY
{
NSLog(@"%2f %2f", scaleX, scaleY);
}
還有一些其他的屬性和方法,想到那個寫那個
//縮放重置
[_lineChartView zoomOut];
// 可以設置dataset依賴左Y軸還是右Y軸,有的時候左右y軸的大小值不一樣,可以進行這么設置
dataSet.axisDependency = AxisDependencyLeft;
// 多系列折線圖數據初始化
LineChartData *data = [[LineChartData alloc] initWithDataSets:dataSets];
// 單系列折線圖數據初始化
LineChartData *data = [[LineChartData alloc] initWithDataSet:dataSet];
經歷了半個月的煎熬,對于折線圖x軸標題重復的問題得到了完美的解決,只需要一個屬性,上面的話沒有刪除,全當自己靈活變通的思路了,也做為一個對自己的警醒,明明是一個屬性的設置,卻因為抵觸情緒不知道嘗試,下面說正事
lineChartView.xAxis.granularity = 1.0;
看下這個屬性的charts的解釋
/**
The minimum interval between axis values.
This can be used to avoid label duplicating when zooming in.
<em>default</em>: 1.0
*/
@property (nonatomic) double granularity;
百度翻譯加自己的理解一下大概意思就是:
x軸標題中間最小的間隔。這樣可以避免在縮放時label文字重復。
然后在設置x軸大小的時候就可以使用通用的方法:
self.lineChartView.xAxis.axisMinimum = data.xMin - 0.8; self.lineChartView.xAxis.axisMaximum = data.xMax + 0.8;
這樣x軸標題重復的問題就完美解決了,也不用跟產品和測試撕逼了。
折線圖暫時想的問題和解決辦法就這么多,如有不對的地方還請多指教
最后demo地址,歡迎大家下載,最好給個star??