You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
463 lines
16 KiB
463 lines
16 KiB
// |
|
// FBYLineGraphView.m |
|
// FBYDataDisplay-iOS |
|
// |
|
// Created by fby on 2018/1/18. |
|
// Copyright © 2018年 FBYDataDisplay-iOS. All rights reserved. |
|
// |
|
|
|
#import "FBYLineGraphView.h" |
|
#import "FBYLineGraphContentView.h" |
|
|
|
/** |
|
* Y轴刻度标签 与 Y轴 之间 空隙 |
|
*/ |
|
#define HORIZON_YMARKLAB_YAXISLINE 10.f |
|
|
|
/** |
|
* Y轴刻度标签 宽度 |
|
*/ |
|
#define YMARKLAB_WIDTH 25.f |
|
|
|
/** |
|
* Y轴刻度标签 高度 |
|
*/ |
|
#define YMARKLAB_HEIGHT 16.f |
|
/** |
|
* X轴刻度标签 宽度 |
|
*/ |
|
|
|
#define XMARKLAB_WIDTH 40.f |
|
|
|
/** |
|
* X轴刻度标签 高度 |
|
*/ |
|
#define XMARKLAB_HEIGHT 16.f |
|
|
|
/** |
|
* 最上边的Y轴刻度标签距离顶部的 距离 |
|
*/ |
|
#define YMARKLAB_TO_TOP 12.f |
|
|
|
@interface FBYLineGraphView() { |
|
|
|
// 数据的 x轴坐标 |
|
NSMutableArray *xMarkValues; |
|
// 最大值 |
|
NSInteger xMarkMaxValue; |
|
// 最小值 |
|
NSInteger xMarkMinValue; |
|
// 值数组 |
|
NSMutableArray *valueArray; |
|
|
|
} |
|
/// 类型 0: 时间(24小时) 1:日期(7天) |
|
@property (nonatomic, assign) int type; |
|
|
|
/** |
|
* 表名标签 |
|
*/ |
|
@property (nonatomic, strong) UILabel *titleLab; |
|
|
|
/** |
|
* 显示折线图的可滑动视图 |
|
*/ |
|
@property (nonatomic, strong) UIScrollView *scrollView; |
|
|
|
/** |
|
* 折线图 |
|
*/ |
|
@property (nonatomic, strong) FBYLineGraphContentView *lineGraphContentView; |
|
|
|
/** |
|
* Y轴刻度标签title |
|
*/ |
|
@property (nonatomic, strong) NSArray *yMarkTitles; |
|
|
|
|
|
/** |
|
* X轴坐标 和 对应的折线图点的值 |
|
*/ |
|
@property (nonatomic, strong) NSArray *xMarkTitlesAndValues; |
|
|
|
|
|
|
|
|
|
/// X轴的 刻度数组 (根据方法需要修改成 24小时的 还是 日期制的) |
|
@property (nonatomic, strong) NSMutableArray *xMarkScaleArr; |
|
|
|
|
|
@end |
|
|
|
@implementation FBYLineGraphView |
|
|
|
- (void)setXScaleMarkLEN:(CGFloat)xScaleMarkLEN { |
|
_xScaleMarkLEN = xScaleMarkLEN; |
|
} |
|
|
|
- (void)setYMarkTitles:(NSArray *)yMarkTitles { |
|
_yMarkTitles = yMarkTitles; |
|
} |
|
|
|
- (void)setMaxValue:(CGFloat)maxValue { |
|
_maxValue = maxValue; |
|
|
|
} |
|
- (void)setMinValue:(CGFloat)minValue { |
|
_minValue = minValue; |
|
} |
|
|
|
- (void)setTitle:(NSString *)title { |
|
_title = title; |
|
|
|
} |
|
|
|
/** |
|
* 设置折线图显示的数据和对应X坐标轴刻度标签 (时间戳 24小时制) |
|
* @param day 哪一天 |
|
* @param xMarkTitlesTimeAndValues 折线图显示的数据 |
|
* @param titleKey 标签(如:1585817374 时间戳) |
|
* @param valueKey 数据 (如:80) |
|
*/ |
|
- (void)setXMarkWithDay:(NSString*)day TitlesTimeAndValues:(NSArray *)xMarkTitlesTimeAndValues titleKey:(NSString *)titleKey valueKey:(NSString *)valueKey{ |
|
|
|
_xMarkTitlesAndValues = xMarkTitlesTimeAndValues; |
|
|
|
xMarkValues = [NSMutableArray array]; |
|
valueArray = [NSMutableArray array]; |
|
|
|
for (NSDictionary *dic in xMarkTitlesTimeAndValues) { |
|
|
|
[xMarkValues addObject:[dic objectForKey:titleKey]]; |
|
[valueArray addObject:[dic objectForKey:valueKey]]; |
|
} |
|
_xMarkScaleArr = [NSMutableArray array]; |
|
|
|
if(YES){ |
|
//等距模式 |
|
NSDateFormatter*dateFormatter = [[NSDateFormatter alloc]init]; |
|
[dateFormatter setDateFormat:@"yyyy-MM-dd"]; |
|
|
|
//日期的零点 |
|
xMarkMinValue = [dateFormatter dateFromString:day].timeIntervalSince1970; |
|
//日期后一天的零点 |
|
xMarkMaxValue = [dateFormatter dateFromString:day].timeIntervalSince1970 + 60*60*24; |
|
|
|
|
|
for (int i = 0; i < 5; i++) { |
|
//坐标显示的刻度 |
|
NSString * xMark = [self getDateFormatWithStr:@"yyyy-MM-dd-H" timeInterval: xMarkMinValue + (60*60*6*i)]; |
|
NSString *Y_Str = [xMark componentsSeparatedByString:@"-"].lastObject; |
|
if(i > 0 && [Y_Str isEqualToString:@"0"]){ |
|
[_xMarkScaleArr addObject:@"24"]; |
|
}else{ |
|
[_xMarkScaleArr addObject:Y_Str]; |
|
} |
|
|
|
} |
|
|
|
}else{ |
|
|
|
// 跨度是多少个小时 |
|
long numHour = 24; |
|
//日期的零点 |
|
xMarkMinValue = [self getDateFormatWithStr:@"yyyy-MM-dd" WithDateStr:day]; |
|
//日期后一天的零点 |
|
xMarkMaxValue = xMarkMinValue + 60*60*24; |
|
|
|
if(_xMarkTitlesAndValues.count > 0){ |
|
//自适应模式 |
|
NSNumber *startTime = [xMarkValues firstObject]; |
|
NSNumber *endTime = [xMarkValues lastObject]; |
|
NSDateFormatter*dateFormatter = [[NSDateFormatter alloc]init]; |
|
[dateFormatter setDateFormat:@"yyyy-MM-dd-HH"]; |
|
//起始的整点时间 (如果不是偶数点的,需要前面补足一个偶数点) |
|
NSString *startIntegerHour = [self getDateFormatWithStr:@"yyyy-MM-dd-HH" timeInterval: startTime.integerValue]; |
|
NSString *tempStartHour = [startIntegerHour componentsSeparatedByString:@"-"].lastObject; |
|
if (([tempStartHour intValue] % 2) != 0){ |
|
startIntegerHour = [self getDateFormatWithStr:@"yyyy-MM-dd-HH" timeInterval: startTime.integerValue-60*60]; |
|
} |
|
xMarkMinValue = [dateFormatter dateFromString:startIntegerHour].timeIntervalSince1970; |
|
//终止的整点时间 (因为大部分都是几点多的情况,需要补足,补足后如果不是偶数点的,需要再补足一个偶数点,这个不可能超过24点的) |
|
NSString *endIntegerHour = [self getDateFormatWithStr:@"yyyy-MM-dd-HH" timeInterval: endTime.integerValue+60*60]; |
|
NSString *tempEndHour = [endIntegerHour componentsSeparatedByString:@"-"].lastObject; |
|
if ( (([tempEndHour intValue] % 2) != 0) |
|
&& ![tempEndHour isEqualToString:@"00"]){ |
|
endIntegerHour = [self getDateFormatWithStr:@"yyyy-MM-dd-HH" timeInterval: endTime.integerValue+60*60*2]; |
|
} |
|
xMarkMaxValue = [dateFormatter dateFromString:endIntegerHour].timeIntervalSince1970; |
|
|
|
|
|
numHour = (xMarkMaxValue - xMarkMinValue) / (60*60); |
|
if (numHour < 1) { |
|
numHour = 1; |
|
xMarkMaxValue = xMarkMinValue + 60*60; |
|
} |
|
} |
|
|
|
// 每个跨度的间隔时间 |
|
NSInteger PerTime = 60*60; |
|
|
|
for (int i = 0; i < numHour+1; i++) { |
|
//坐标显示的刻度 |
|
NSString * xMark = [self getDateFormatWithStr:@"yyyy-MM-dd-H" timeInterval: xMarkMinValue + (PerTime*i)]; |
|
NSString *Y_Str = [xMark componentsSeparatedByString:@"-"].lastObject; |
|
if(i > 0 && [Y_Str isEqualToString:@"0"]){ |
|
[_xMarkScaleArr addObject:@"24"]; |
|
}else{ |
|
[_xMarkScaleArr addObject:Y_Str]; |
|
} |
|
|
|
} |
|
//多少个X轴的分割线 |
|
int count = 6; |
|
if(_xMarkScaleArr.count > count + 2){ |
|
_xMarkScaleArr = [self setArrWithArray:_xMarkScaleArr AndWantCount:count]; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
_xScaleMarkLEN = (self.frame.size.width - HORIZON_YMARKLAB_YAXISLINE - YMARKLAB_WIDTH - XMARKLAB_WIDTH / 2.0) / (_xMarkScaleArr.count - 1); |
|
} |
|
//抽离成想要的个数 |
|
-(NSMutableArray*)setArrWithArray:(NSMutableArray*)tempArr AndWantCount:(int)count{ |
|
NSInteger tempCount = (tempArr.count - 2) % (count-2); |
|
for (int i = 1 ; i < tempArr.count-1; i++) { |
|
if((i%(count-2)) != 0){ |
|
tempArr[i] = @""; |
|
} |
|
} |
|
return tempArr; |
|
|
|
} |
|
|
|
/** |
|
* 设置折线图显示的数据和对应X坐标轴刻度标签 (日期 eg: 2020-04-02 日期制) |
|
* |
|
* @param xMarkTitlesFDayAndValues 折线图显示的数据 |
|
* @param titleKey 标签(日期 eg: 2020-04-02) |
|
* @param valueKey 数据 (如:80) |
|
*/ |
|
- (void)setXMarkTitlesDayAndValues:(NSArray *)xMarkTitlesFDayAndValues titleKey:(NSString *)titleKey valueKey:(NSString *)valueKey{ |
|
//归整成 当天的 00:00 |
|
NSMutableArray *arr = [NSMutableArray array]; |
|
NSDateFormatter*dateFormatter = [[NSDateFormatter alloc]init]; |
|
[dateFormatter setDateFormat:@"yyyy-MM-dd"]; |
|
for (NSDictionary *item in xMarkTitlesFDayAndValues) |
|
{ |
|
NSNumber *timeNumber = item[titleKey]; |
|
NSString *dayStr = [self getDateFormatWithStr:@"yyyy-MM-dd" date:[NSDate dateWithTimeIntervalSince1970:timeNumber.doubleValue]]; |
|
NSNumber *newTimeNumber = @([dateFormatter dateFromString:dayStr].timeIntervalSince1970); |
|
NSMutableDictionary *tempDic = [NSMutableDictionary dictionaryWithDictionary:item]; |
|
[tempDic setValue:newTimeNumber forKey:titleKey]; |
|
[arr addObject:tempDic]; |
|
} |
|
|
|
_xMarkTitlesAndValues = arr; |
|
|
|
xMarkValues = [NSMutableArray array]; |
|
valueArray = [NSMutableArray array]; |
|
|
|
//其余没数据的天数补0 |
|
//是为 日期(7天) 格式 |
|
_type = 1; |
|
|
|
|
|
int howManyDays = 7; |
|
|
|
_xMarkScaleArr = [NSMutableArray array]; |
|
for (int i = 0; i < howManyDays; i++) |
|
{ |
|
NSString *dayStr; |
|
NSString *dayStr1; |
|
if(i == howManyDays-1){ |
|
//今天 |
|
dayStr = [self getDateFormatWithStr:@"yyyy-MM-dd" date:[NSDate date]]; |
|
// [_xMarkScaleArr addObject:[dayStr componentsSeparatedByString:@"-"].lastObject]; |
|
dayStr1 = [self getDateFormatWithStr:@"MM.dd" date:[NSDate date]]; |
|
[_xMarkScaleArr addObject:@"今天"]; |
|
|
|
xMarkMaxValue = [dateFormatter dateFromString:dayStr].timeIntervalSince1970; |
|
} |
|
else |
|
{ |
|
//几天前 |
|
dayStr = [self getDateFormatWithStr:@"yyyy-MM-dd" date: [self ddpGetExpectTimestamp:0 month:0 day:i+1-howManyDays]]; |
|
//[_xMarkScaleArr addObject:[dayStr componentsSeparatedByString:@"-"].lastObject]; |
|
dayStr1 = [self getDateFormatWithStr:@"MM.dd" date: [self ddpGetExpectTimestamp:0 month:0 day:i+1-howManyDays]]; |
|
[_xMarkScaleArr addObject:dayStr1]; |
|
|
|
if(i==0){ |
|
xMarkMinValue = [dateFormatter dateFromString:dayStr].timeIntervalSince1970; |
|
} |
|
} |
|
NSNumber *tempTimeStamp = @([dateFormatter dateFromString:dayStr].timeIntervalSince1970); |
|
NSNumber *tempData = @(0); |
|
for (NSDictionary *dic in _xMarkTitlesAndValues) { |
|
if ([[dic objectForKey:titleKey] integerValue] == tempTimeStamp.integerValue){ |
|
tempData = [dic objectForKey:valueKey]; |
|
} |
|
} |
|
|
|
[xMarkValues addObject:tempTimeStamp]; |
|
[valueArray addObject:tempData]; |
|
|
|
} |
|
NSLog(@"_xMarkScaleArr: %@",_xMarkScaleArr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
#pragma mark 绘图 |
|
- (void)mapping { |
|
|
|
static CGFloat topToContainView = 0.f; |
|
static CGFloat bottomToContainView = 0.f; |
|
if (self.title) { |
|
|
|
self.titleLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 5, CGRectGetWidth(self.frame), 20)]; |
|
self.titleLab.text = self.title; |
|
self.titleLab.textColor = [UIColor blackColor]; |
|
self.titleLab.font = [UIFont systemFontOfSize:15]; |
|
self.titleLab.textAlignment = NSTextAlignmentCenter; |
|
[self addSubview:self.titleLab]; |
|
topToContainView = 25; |
|
} |
|
if(self.X_UnintTitle){ |
|
bottomToContainView = 21; |
|
UILabel *unintLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,self.frame.size.height - bottomToContainView, CGRectGetWidth(self.frame), bottomToContainView)]; |
|
unintLabel.text = _X_UnintTitle; |
|
unintLabel.textColor = [UIColor colorWithRed:102.0f/255.0f green:102.0f/255.0f blue:102.0f/255.0f alpha:1.0f]; |
|
unintLabel.font = [UIFont systemFontOfSize:12]; |
|
unintLabel.textAlignment = NSTextAlignmentCenter; |
|
[self addSubview:unintLabel]; |
|
|
|
} |
|
|
|
|
|
if (!self.xMarkTitlesAndValues) { |
|
|
|
xMarkValues = @[@1,@2,@3,@4,@5].mutableCopy; |
|
valueArray = @[@2,@2,@2,@2,@2].mutableCopy; |
|
|
|
} |
|
|
|
|
|
if (!self.yMarkTitles) { |
|
if(_Ycount == 0){ |
|
_Ycount = 6; |
|
} |
|
NSMutableArray *tempYMarkTitles = [NSMutableArray array]; |
|
CGFloat Yunint = (_maxValue - _minValue) / (_Ycount-1); |
|
for (int i = 0; i < _Ycount; i++) { |
|
// [tempYMarkTitles addObject:[NSString stringWithFormat:@"%@",[NSNumber numberWithFloat:_minValue + (Yunint * i)]]]; |
|
[tempYMarkTitles addObject:[NSString stringWithFormat:@"%.0f",_minValue + (Yunint * i)]]; |
|
} |
|
// [tempYMarkTitles addObject:@""]; |
|
// LineGraphView.yMarkTitles = @[@"0",@"20",@"40",@"60",@"80",@"100"]; // Y轴刻度标签 |
|
_yMarkTitles = [tempYMarkTitles copy]; |
|
// if(tempYMarkTitles.count == 0){ |
|
// self.yMarkTitles = @[@0,@1,@2,@3,@4,@5]; |
|
// } |
|
|
|
} |
|
|
|
|
|
if (self.maxValue == 0) { |
|
self.maxValue = 5; |
|
|
|
} |
|
|
|
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, topToContainView, self.frame.size.width,self.frame.size.height - topToContainView-bottomToContainView)]; |
|
[self.scrollView setShowsHorizontalScrollIndicator:NO]; |
|
[self.scrollView setShowsVerticalScrollIndicator:NO]; |
|
[self addSubview:self.scrollView]; |
|
|
|
self.lineGraphContentView = [[FBYLineGraphContentView alloc] initWithFrame:self.scrollView.bounds]; |
|
self.lineGraphContentView.chartType = self.type; |
|
self.lineGraphContentView.MainColor = self.MainColor; |
|
self.lineGraphContentView.XYAxisColor = self.XYAxisColor; |
|
self.lineGraphContentView.yMarkTitles = self.yMarkTitles; |
|
self.lineGraphContentView.minValue = self.minValue; |
|
self.lineGraphContentView.maxValue = self.maxValue; |
|
self.lineGraphContentView.upperValue = self.upperValue; |
|
self.lineGraphContentView.lowerValue = self.lowerValue; |
|
self.lineGraphContentView.xMarkScaleArr = self.xMarkScaleArr; |
|
self.lineGraphContentView.xMarkValues = xMarkValues; |
|
self.lineGraphContentView.xMarkmaxValue = xMarkMaxValue; |
|
self.lineGraphContentView.xMarkminValue = xMarkMinValue; |
|
self.lineGraphContentView.xScaleMarkLEN = self.xScaleMarkLEN; |
|
self.lineGraphContentView.valueArray = valueArray; |
|
self.lineGraphContentView.maxValue = self.maxValue; |
|
|
|
[self.scrollView addSubview:self.lineGraphContentView]; |
|
|
|
[self.lineGraphContentView mapping]; |
|
|
|
self.scrollView.contentSize = self.lineGraphContentView.bounds.size; |
|
|
|
} |
|
|
|
#pragma mark 更新数据 |
|
- (void)reloadDatas { |
|
[self.lineGraphContentView reloadDatas]; |
|
} |
|
|
|
- (NSTimeInterval)getDateFormatWithStr:(NSString *)dateFormat WithDateStr:(NSString*)dayStr{ |
|
NSDateFormatter*dateFormatter = [[NSDateFormatter alloc]init]; |
|
[dateFormatter setDateFormat:dateFormat]; |
|
return [dateFormatter dateFromString:dayStr].timeIntervalSince1970; |
|
} |
|
|
|
- (NSString *)getDateFormatWithStr:(NSString *)dateFormat timeInterval:(NSTimeInterval)timeInterval{ |
|
return [self getDateFormatWithStr:dateFormat date:[NSDate dateWithTimeIntervalSince1970:timeInterval]]; |
|
} |
|
- (NSString *)getDateFormatWithStr:(NSString *)dateFormat date:(NSDate *)date{ |
|
NSDateFormatter*dateFormatter = [[NSDateFormatter alloc]init]; |
|
[dateFormatter setDateFormat:dateFormat]; |
|
return [dateFormatter stringFromDate:date]; |
|
} |
|
///< 获取当前时间的: 前一周(day:-7)丶前一个月(month:-30)丶前一年(year:-1)的时间 NSDate |
|
- (NSDate *)ddpGetExpectTimestamp:(NSInteger)year month:(NSUInteger)month day:(NSUInteger)day { |
|
|
|
///< 当前时间 |
|
NSDate *currentdata = [NSDate date]; |
|
|
|
///< NSCalendar -- 日历类,它提供了大部分的日期计算接口,并且允许您在NSDate和NSDateComponents之间转换 |
|
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; |
|
|
|
/* |
|
///< NSDateComponents:时间容器,一个包含了详细的年月日时分秒的容器。 |
|
///< 下例:获取指定日期的年,月,日 |
|
NSDateComponents *comps = nil; |
|
comps = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:currentdata]; |
|
NSLog(@"年 year = %ld",comps.year); |
|
NSLog(@"月 month = %ld",comps.month); |
|
NSLog(@"日 day = %ld",comps.day);*/ |
|
|
|
|
|
NSDateComponents *datecomps = [[NSDateComponents alloc] init]; |
|
[datecomps setYear:year?:0]; |
|
[datecomps setMonth:month?:0]; |
|
[datecomps setDay:day?:0]; |
|
|
|
///< dateByAddingComponents: 在参数date基础上,增加一个NSDateComponents类型的时间增量 |
|
NSDate *calculatedate = [calendar dateByAddingComponents:datecomps toDate:currentdata options:0]; |
|
|
|
// ///< 打印推算时间 |
|
// NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; |
|
// [formatter setDateFormat:@"yyyy-MM-dd hh:mm:ss"]; |
|
// NSString *calculateStr = [formatter stringFromDate:calculatedate]; |
|
// |
|
// xLog(@"calculateStr 推算时间: %@",calculateStr ); |
|
// |
|
// ///< 预期的推算时间 |
|
// NSString *result = [NSString stringWithFormat:@"%ld", (long)[calculatedate timeIntervalSince1970]]; |
|
|
|
return calculatedate; |
|
} |
|
@end
|
|
|