数据大屏中的折线图的一个典型场景是根据查询的统计时间范围不同显示不同时间粒度的折线图,如:按月、按年,以及分时图等,如果在以年为周期的图表中仍然显示分钟、小时数据,无疑是怪异的。

以月为粒度的折线图
以月为粒度的折线图
以天为粒度的折线图
以天为粒度的折线图
以小时为粒度的折线图
以小时为粒度的折线图

因此,就需要对传入的统计时间范围参数做一个判断,既在后端的接口层返回对应时间粒度的数据,也在前端的图表展示中显示对应的维度、粒度信息。而倘若后端接口层不做聚合统计,甚至还需要在前端层面进行数据的相应处理。

废话不多说,直接上代码:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
getDateDimension(startDate: Date | string, endDate: Date | string): DateDimension { const duration = moment.duration(moment(endDate).diff(moment(startDate))); // by year if (duration.years() > 1) { return 'year'; } // by month if (duration.months() > 0) { return 'month'; } // by day if (duration.days() > 0) { return 'day'; } // by hour return 'hour'; }
getDateDimension(startDate: Date | string, endDate: Date | string): DateDimension { const duration = moment.duration(moment(endDate).diff(moment(startDate))); // by year if (duration.years() > 1) { return 'year'; } // by month if (duration.months() > 0) { return 'month'; } // by day if (duration.days() > 0) { return 'day'; } // by hour return 'hour'; }

算法很简单,无需多言,核心是moment.duration调用,计算起止时间的差值,返回一个时间对象。实际上,在聚合查询、图表操作中,大量用到moment类库的不同方法,堪称时间操作的神器。

此方法可根据实际需求进行变化、改进,不再赘述。

计算出时间粒度后,便是图表的展示了。在文章开头的例子中,如果在以年为周期的图表中,横坐标却显示为具体的日期,未免太突兀;同样,在分时图中,显示年、月、日,也是不合适的,仅需显示“时:分”即可。因此,还需做进一步判断:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
getChartDateTitle(title: string, dateDimension: DateDimension, separator = '-'): string { let dates: string[]; switch (dateDimension) { case 'year': return `${title}年`; case 'month': dates = title.split(separator); return `${dates[0]}${dates[1]}月`; case 'hour': return title; default: dates = title.split(separator); return `${dates[0]}${dates[1]}日`; } }
getChartDateTitle(title: string, dateDimension: DateDimension, separator = '-'): string { let dates: string[]; switch (dateDimension) { case 'year': return `${title}年`; case 'month': dates = title.split(separator); return `${dates[0]}年${dates[1]}月`; case 'hour': return title; default: dates = title.split(separator); return `${dates[0]}月${dates[1]}日`; } }

结合接口数据处理:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
this.pvData = res.map((item) => { switch (this.dateDimension) { case 'day': const temp = item.date.split('-'); temp.shift(); item.date = temp.join('-'); break; case 'hour': item.date = item.date.split(' ')[1]; } return item; });
this.pvData = res.map((item) => { switch (this.dateDimension) { case 'day': const temp = item.date.split('-'); temp.shift(); item.date = temp.join('-'); break; case 'hour': item.date = item.date.split(' ')[1]; } return item; });

以上,即可实现根据不同时间范围显示不同时间粒度的统计数据。[]~( ̄▽ ̄)~*

 

注:

后端接口层需做同样处理,根据不同时间粒度执行不同的聚合查询,本文不再详述。