【问题标题】:Displaying data in different timezone显示不同时区的数据
【发布时间】:2020-03-28 11:46:59
【问题描述】:

总结

我收集了大量不同日期时间的数据。目前我已经能够将我的所有数据分组以在本地时区正确显示;然而,当试图在不同的时区显示这些数据时,lineChart 上的线条会变得不连贯,并且它们之间的连接不像在本地时区那样平滑。

我在这里找到了这个链接,详细说明了一个可能的解决方案,但遗憾的是,如果我没有复制我的整个数据集,时间从 UTC 偏移,然后正常一次,这将无法工作。我拥有的数据不仅用于几个图表中以获取有关趋势和统计数据的见解,而且还有一个用于显示/编辑/审查特定数据成员的原始表。因此,将其中一个转换为 utc 时间并计算 utc 时间的时间变化会抛出另一个。

https://groups.google.com/forum/#!msg/d3-js/iWmP9Npv2Go/xyypdLjWu2QJ

我的问题是:有没有办法跨时区转换日期时间数据并让 dc.js 尊重您想要显示的时区。我希望调整后的图表看起来与本地图表的线条相同基于时区不是片面的。

代码和照片

小提琴:https://jsfiddle.net/spacarar/j0urt9sy/49/

这是我当地时区的正确显示图像。线条是日期之间的平滑过渡。

这是任何其他时区的错误显示图像(取决于我本地的哪一侧将方向从左倾变为右倾)

我的数据的简化版本如下所示:

var data = [
  {
    value: 42,
    datetime: '2019-10-24T07:18:00.000000'
  },
  {
    value: 10,
    datetime: '2019-10-24T07:19:12.000000'
  },
  {
    value: 12,
    datetime: '2019-10-29T04:18:00.000000'
  },
  {
    value: 8,
    datetime: '2019-10-29T09:18:00.000000'
  }
]

然后我伪造组来填充数据中可能不存在的任何日期,并使用时刻时区对其进行翻译,最终得到与此类似的数据结构

{
  value: 0,
  datetime: moment timezone object with full datetime,
  date: moment timezone object representing only date (0 hours, minutes, seconds, ms)
}

然后使用这个虚假的分组/固定数据创建带有以下代码的图表

var ndx = dc.crossfilter(fakeGroupedData)

var dateDim = ndx.dimension(dc.pluck('date'))
var top = dateDim.top(1)[0] ? dateDim.top(1)[0].date : null
var bottom = dateDim.bottom(1)[0] ? dateDim.bottom(1)[0].date : null

var chart = dc.lineChart('#date-chart')
chart.yAxis().tickFormat(dc.d3.format(',.0f'))
chart.xAxis().ticks(10).tickFormat(d => moment(d).format('M/D'))

chart.dimension(dateDim)
  .group(dateDim.group().reduceSum(dc.pluck('value')))
  .x(dc.d3.scaleTime().domain([bottom, top]).nice())
  .elasticY(true)
  .renderArea(true)
  .render()

【问题讨论】:

    标签: d3.js momentjs dc.js moment-timezone


    【解决方案1】:

    关于日期填写的几点说明。

    1. 这不是“假组”的通常含义。您正在填写源数据,并且您所有的交叉过滤器组都是完全“真实的”:)

    2. 以比您想要显示的分辨率更高的分辨率进行填充没有任何意义。为了简化问题,我将您的代码更改为按天填充,它的工作原理完全相同:

      let start = moment.tz(startDate, tzSelection).startOf('day')
      let end = moment.tz(endDate, tzSelection).endOf('day')
      let hours = end.diff(start, 'days')
      for (let i = 0; i < hours; i++) {
        let fakeTime = moment(start).add(i, 'days')
        let date = moment(fakeTime.format('YYYY-MM-DD'))
        fakeGroupedData.push({
          value: 0,
          datetime: fakeTime,
          date
        })
      }
      

    使用d3-time 可能更容易,因为它与 dc.js 集成得更紧密,但我不想对您的代码进行大的更改。

    但是,您本质上是按天量化的,因此您可以设置维度以量化到当前时区中一天的开始,这将修复您的图表:

    var dateDim = ndx.dimension(d => d3.timeDay(dc.pluck('date')(d)))
    

    如果这样做,则无需修改输入日期:

    el.date = el.datetime //.clone().startOf('day')
    

    D3 将截断到当前日期,然后交叉过滤器将按该分辨率分箱。

    https://jsfiddle.net/gordonwoodhull/Lxvcoq3h/19/

    请注意,它将两个 10/29 条目合并为一个。

    在我的时区 UTC-5 中,startOf('day') 舍入的那一刻导致这些条目中的第一个在 28 日登陆,这与您所说的您想要的相符:

    https://jsfiddle.net/gordonwoodhull/Lxvcoq3h/21/

    您必须决定哪一个适合您的应用程序。要点是,如果您在本地时区显示图表,则应将数据量化为本地天数。

    【讨论】:

    • 再次感谢 Gordan,非常感谢。 ndx.dimension(d =&gt; d3.timeDay(dc.pluck('date')(d))) 绝对是我寻找的关键。
    猜你喜欢
    • 2020-09-15
    • 2010-11-26
    • 2017-12-30
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 2012-07-22
    • 2018-01-09
    相关资源
    最近更新 更多