首页 > 解决方案 > 显示不同时区的数据

问题描述

概括

我有大量不同日期时间的数据。目前我已经能够将我的所有数据分组以在本地时区正确显示;然而,当试图在不同的时区显示这些数据时,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.jsmomentjsdc.jsmoment-timezone

解决方案


关于日期填写的几点。

  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 将截断到当天,然后交叉过滤器将以该分辨率进行 bin。

白天装箱

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

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

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

时刻舍入到一天,然后按天分类

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

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


推荐阅读