// // 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:@""]; // 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