如何让 D3 数据驱动文档在正确的时区显示 moment.js 日期时间?

How do I get D3 Data Driven Document to display a moment.js datetime in the correct time zone?

我正在开发一个 AngularJS 单页应用程序,它使用 D3 图表来显示在世界各地不同时区记录的数据。图表上的时间轴需要显示其原始时区的时间。

要绘制的数据是一组值、时间戳对。时间戳包含自己的时区信息,并以 ISO format 编码(例如 "2003-12-14T12:00:00.000+08:00")。所以 json 看起来像这样:

"values": [
   ["2003-12-14T12:00:00.000+08:00", 10],
   ["2003-12-14T13:00:00.000+08:00", 20],
   ["2003-12-14T14:00:00.000+08:00", 30],
   ["2003-12-14T15:00:00.000+08:00", 40],
   ["2003-12-14T16:00:00.000+08:00", 50]
]

然后将时间戳和值添加到对象中,其中时间戳转换为时刻:

data = values[1];
timeStamp = moment.parseZone(values[0]);

然后将这些样本传递给 D3 进行显示。但是,当它们传递给 D3 时,时间刻度显示为本地浏览器时间。这不好 - 我不知道如何让它在正确的时区显示数据。

我尝试使用自定义方法设置 xAxis.tickFormat,但传递给它的时间是标准 Javascript 日期对象,在当地时区。

此外,时区可能会在图表中间发生变化(由于夏令时),因此不能简单地保持时区偏移值并进行手动调整。

答案是编写一个方法来计算和 returns 刻度值,以及类似的刻度格式,如来自@LarsKotthoff 的 this link 给出的那样。

最终代码需要是这样的:

xAxis = d3.svg.axis()
    .scale(xScale)
    .tickValues(calculateTickValue)
    .tickFormat(getTickFormat);

var getTickFormat = function(date){
    var diff = date.format("DD") != previousDate.format("DD");                    
    if (diff){
        previousDate = date;
        return date.format("MMM Do, HH:mm");
    }
    return date.format(tickFormat);
}

var calculateTickValue = function(){
    var startTime = scope.segment.startTime;
    var endTime = scope.segment.endTime;
    var tickValues = [];
    var difference = moment.duration(endTime.diff(startTime));
    var maximumTicks = calculateMaximumTicks(); 
    if (difference.asHours() >= maximumTicks){
       tickValues = calculateHoursTicks(startTime, endTime, maximumTicks);
       tickFormat = "HH:mm";
    }
    else {
        tickValues = caclulateMinutesTicks(startTime, endTime, maximumTicks);
        tickFormat = "HH:mm";
    }

    previousDate = startTime;
    return tickValues;
}

显然,根据您需要的比例,可以自定义年、月、日、小时等。