D3.js 核心概念——数据处理与分析(十一)时间边距计算器之二

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情


系列文章可以查看《数据可视化》专栏


时间修约

时间边距计算器 interval 是一个方法,可以直接调用 interval([date]) 以计算出给定时间 date 所属的时间间距的下界,即一个 Date 对象。

// 基于字符串创建一个 Date 对象
// 最后添加 Z 后缀采用 UTC 协调世界时
const utcDateObj = new Date("2022-02-02T06:40:10.123Z");
console.log(utcDateObj); // "2022-02-04T20:40:10.123Z"

// 创建不同间距的 interval,然后直接调用,并指定入参为 utcDateObj
// 由于入参时间是 UTC 格式,所以采用相应的方法创建时距器 interval
const year = d3.utcYear(utcDateObj);
const month = d3.utcMonth(utcDateObj);
const hour = d3.utcHour(utcDateObj);
const minute = d3.utcMinute(utcDateObj);
const second = d3.utcSecond(utcDateObj);
const millisecond = d3.utcMillisecond(utcDateObj);

// 打印不同 interval 调用的结果
// 返回给定时间所属的时间间距的下界,它是一个以该时间创建的 Date 对象,打印出时会自动转变为字符串形式
console.log("utcYear Lower Boundary: ", year);
console.log("utcMonth Lower Boundary: ", month);
console.log("utcHour Lower Boundary: ", hour);
console.log("utcMinute Lower Boundary: ", minute);
console.log("utcSecond Lower Boundary: ", second);
console.log("utcMillisecond Lower Boundary: ", millisecond);
复制代码

控制台输出结果如下,具体代码演示可以查看这个 Codepen

d3-interval.png

以上示例先基于字符串 2022-02-02T06:40:10.123Z 创建的 Date 对象 utcDateObj(它采用 UTC 时间)。创建一系列相应的 interval,然后直接调用,并指定入参为创建的 Date 对象 utcDateObj。这些 interval 分别返回一个新的 Date 对象,它们分别表示 utcDateObj 在相应时间尺度下的下边界时间。可以将这些时距器看作是对当前时间的转换,从入参的 Date 对象提取特定的时间字段,如所在的月份,然后以这个月的第一天的凌晨零点创建一个新的 Date 对象,这个新的 Date 对象表示这个月。这在创建时间轴刻度很实用,如下图是以天为间距、以月为间距、以年为间距的三种 intervals 的示意图:

d3-interval-illustration.png

? 如果可选参数 date 省略,则采用当前时间 new Date() 作为默认入参。直接调用 interval(date) 相当于使用该时距器的方法 interval.floor(date),两者不同在于后者 interval.floor() 必须传入参数。

时间边距计算器 interval 也是一个对象,有多种方法用于获取满足不同需求的 Date 对象:

  • 方法 interval.floor(date) 用于计算出给定时间 date 所属的时间间距的下界

    对于时间尺度大于小时的 interval,返回的 Date 对象最后的时间点都是 12:00 AM 即凌晨零点,例如 d3.timeDay.floor(date) 返回的是以 date 日期当天的凌晨零点(当地时)为时间点的一个 Date 对象

    ? 由于返回的 Date 对象是 interval 时间尺度的下界,所以 interval.floor(interval.floor(date) - 1) 返回的是上一个间隔的下界,例如 d3.timeDay.floor(d3.timeDay.floor(date) - 1) 返回的是 date 日期前一天的凌晨零点(当地时)

    d3-interval-floor.png

    ⚠️ 比较日期是否相等时,应该先转变为数值

    // 如果入参 date 已经是边距上的日期,即当天的凌晨零点,则函数返回 true
    function isDay(date) {
      return +d3.timeDay.floor(date) === +date;
    }
    复制代码
  • 方法 interval.ceil(date) 用于计算出给定时间 date 所属的时间间距的上界

    例如 d3.timeDay.ceil(date) 返回的是以 date 日期后一天的凌晨零点(当地时)为时间点的一个 Date 对象

    d3-interval-ceil.png

  • 方法 interval.round(date) 类似于对时间 date 进行「四舍五入」操作,根据入参 date 与所属的时间间距的中点的距离,决定返回时间间距的上界还是下界

    例如 d3.timeDay.round(date) 如果给定时间 date 在中午或之前 12:00 PM,则返回上界,即返回的是以 date 日期当天的凌晨零点(当地时)为时间点的一个 Date 对象;如果给定时间 date 在中午之后 12:00 PM,则返回下界,即返回 date 日期后一天的凌晨零点(当地时)为时间点的一个 Date 对象

    d3-interval-round.png

    d3-interval-round-illustration.png

interval 除了可以对时间进行修约,获取在特定时间尺度里的上界和下界,还可以对时间进行更多的操作:

  • 方法 interval.offset(date[, step]) 对入参的时间 date 进行偏移处理,然后返回一个基于偏移后的时间点所创建的 Date 对象,不必是边界值

    第一个参数 date 是一个 Date 对象,作为参照时间,偏移的起始点

    第二个(可选)参数 step 是一个整数(如果入参 step 不是整数,在内部会先对其进行向下修约),用以设置偏移量(其单位是因 interval 的时间尺度而异的)。默认值是 1,可以是负值。

    例如 date 的时间点是 5:30 PM,则 d3.timeDay.offset(date, 1) 返回一个 Date 对象,其时间点是明天的 5:30 PM

    ? 如果 step0 则该方法返回一个时间点与 date 相同的新的 Date 对象

  • 方法 interval.range(start, stop[, step]) 返回一个包含一系列 Date 对象的数组,这些 Date 对象在特定的时间范围内,且间隔都是相同的,而且这些 Date 对象是 interval 时间尺度下的下界值

    第一个、第二个参数 start(包含) 和 stop(不包括)用于设置时间范围

    第三个(可选)参数 step 是一个整数(如果入参 step 不是整数,在内部会先对其进行向下修约),用于设置步长,即每距离多长的时间(其单位是因 interval 的时间尺度而异的)采集一个时间点,生成一个 Date 对象。step 默认值为 1

    例如 d3.timeDay.range(start, stop) 返回数组的第一个 Date 对象,其时间点是大于 start 时间点(如果 start 时间点正好是凌晨零点,则第一个时间点可以是 start),且是 interval 时间尺度下的下边界;而最后一个 Date 对象,其时间点是小于 stop 时间点,也是 interval 时间尺度下的下边界

    d3-interval-range.png

    d3-interval-range-illustration.png

    ? D3 还为不同的时间尺度下的时距器的方法 interval.range() 提供了相应的语法糖 :

    • d3.timeMilliseconds(start, stop[, step])d3.utcMilliseconds(start, stop[, step]) 时间尺度为毫秒级别

    • d3.timeSeconds(start, stop[, step])d3.utcSeconds(start, stop[, step]) 时间尺度为秒级别

    • d3.timeMinutes(start, stop[, step])d3.utcMinutes(start, stop[, step]) 时间尺度为分钟级别

    • d3.timeHours(start, stop[, step])d3.utcHours(start, stop[, step]) 时间尺度为小时级别

    • d3.timeDays(start, stop[, step])d3.utcDays(start, stop[, step]) 时间尺度为天级别

    • d3.timeWeeks(start, stop[, step])d3.utcWeeks(start, stop[, step]) 时间尺度为周级别
      此外对于按周计算间距的情况,由于可以按照不同起点来计算新的一周,所以提供了 7 种不同的方法:

      • d3.timeSundays(start, stop[, step])d3.utcSundays(start, stop[, step]) 时间尺度为周级别,且以周日为每一周的开始
      • d3.timeMondays(start, stop[, step])d3.utcMondays(start, stop[, step]) 以周一为每一周的开始
      • d3.timeTuesdays(start, stop[, step])d3.utcTuesdays(start, stop[, step]) 以周二为每一周的开始
      • d3.timeWednesdays(start, stop[, step])d3.utcWednesdays(start, stop[, step]) 以周三为每一周的开始
      • d3.timeThursdays(start, stop[, step])d3.utcThursdays(start, stop[, step]) 以周四为每一周的开始
      • d3.timeFridays(start, stop[, step])d3.utcFridays(start, stop[, step]) 以周五为每一周的开始
      • d3.timeSaturdays(start, stop[, step])d3.utcSaturdays(start, stop[, step]) 以周日为每一周的开始
    • d3.timeMonths(start, stop[, step])d3.utcMonths(start, stop[, step]) 时间尺度为月级别

    • d3.timeYears(start, stop[, step])d3.utcYears(start, stop[, step]) 时间尺度为年级别

    以上方法中时间的名称为复数,这是为了表示这些方法的返回值是一个数组,含有多个 Date 对象

  • 方法 interval.count(start, end) 返回在 start(不包含)和 end(包含)时间范围内,在 interval 所在的时间尺度下,间距的个数

    const start = '2021-04-08T15:20:05.123Z';
    const end = '2021-04-15T15:20:05.123Z';
    daysBetween = d3.timeDay.count(start, end); // 7
    复制代码

    ? 开始和结束时间点是否包含在内,这一点与 interval.range() 有所不同,因为 interval.count() 统计得到的是基于 0 为索引的间距的数量

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享