之前一直都说要写关于绘制折线和柱状图的相关文章,之前在忙新的项目,这几天不忙,也是之前那篇文章有小伙伴问我折线与柱状图绘制的相关问题,说一些自己研究Charts的经验,仅代表个人观点,如有错误,请多指正,下面进入正题。
首先看一下目前折线图的效果
这个效果是经历了将近一个月的时间,为了有这样的效果,我翻遍了的文章,问了很多人,技术群,这个效果是在产品经理每周叨叨叨逼出来的,不要问我为什么这么说,真的是每天都追着我改改改,优化优化优化,所以现在就有了这样的效果,下面是代码,代码里面该标注释的地方都有注释,不要问我有github链接么,所有代码都在这里,试试就知道了,讲真,我不骗人,毕竟试试又不会怀孕~~
声明一下绘制的LineChartView只有左Y轴,没有右Y轴,右Y轴设置也很简单,请参考左Y轴,但是一般只要左Y轴就好了。
首先是初始化,喜欢用懒加载初始化,因为页面有好几个图表,第一时间不一定用得到折线图,初始化只有一句话,是不是很爽,别想太多,因为好几个模块用到的东西都一样,就放在一个工具类里面了,MBSChartTool这个工具类,有文章,全是代码以及注释。。。这个工具类只是为了偷懒,最后控制器还有遵守一个代理
@interface ViewController ()
@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", @"", @""];
NSArray *array1 = @[@"998.5", @"1014.5", @"249", @"", @""];
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.
default: 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