使用D3(v4,升级到v5也是一个选项),我正在绘制时间间隔的时间序列。数据的持续时间未知,通常是几秒钟,我们有一个开始日期戳和结束日期戳。
我目前正在做的生成x轴的方法是这样的,其中startTime
和endTime
是数字时间戳,width
和height
是数字和xAxisGroupSelection
是D3选择:
const xScale = d3.scaleTime()
.domain([0, startTime - endTime)
.range([0, width])
const xAxis = d3.axisBottom()
.scale(this.xScale)
xAxisGroupSelection
.attr('transform', `translate(0, ${height})`)
.call(xAxis)
这样做非常好,它为数字提供了合理的格式。例如,它的样式为:01
秒,毫秒为.500
,如果我得到一个相当长的间隔,持续数分钟或数小时,它就会处理它。
问题是,由于它读取0
时间戳,因此会在配置文件的开头添加1970
年标签。这当然是0
时间戳的正确年份,但我不希望它显示任何年的时间序列秒。有没有办法使用D3配置我可以保持默认时间格式,但不添加年份(或月,日等)的刻度?
<g class="axis-group x-axis" transform="translate(0, -12)" fill="none" font-size="10" font-family="sans-serif" text-anchor="middle">
<path class="domain" stroke="#000" d="M0.5,2V0.5H0.5V2"></path>
<g class="tick" opacity="1" transform="translate(0.5,0)">
<line stroke="#000" y2="2"></line>
<text fill="#000" y="5" dy="0.71em">1970</text> <!-- <=== -->
</g>
<g class="tick" opacity="1" transform="translate(0.5,0)">
<line stroke="#000" y2="2"></line>
<text fill="#000" y="5" dy="0.71em">.500</text>
</g>
<g class="tick" opacity="1" transform="translate(0.5,0)">
<line stroke="#000" y2="2"></line>
<text fill="#000" y="5" dy="0.71em">:01</text>
</g>
<g class="tick" opacity="1" transform="translate(0.5,0)">
<line stroke="#000" y2="2"></line>
<text fill="#000" y="5" dy="0.71em">.500</text>
</g>
显然有很多迂回方式可以删除或修改它,从使用CSS第一子规则隐藏它到在D3中手动选择它并修改它的值,但是我想知道它是否&# 39;可以做到 使用D3比例/轴/格式/时间API的干净方式。
我可以告诉D3的轴刻度线生成器忽略大于分钟的时间单位吗?我已经通过了the docs for D3 time scales但却找不到任何东西。我认为可以使用Time.range()
, but the docs aren't giving me many clues on how。
更新:看起来我需要创建一个自定义函数来传递给.tickFormat()
,类似于this example,但是复制了一个带有截断点的默认时间格式化程序添加到条件逻辑。接下来的问题是:我在哪里可以找到默认的D3时间格式逻辑...
答案 0 :(得分:1)
查看D3源代码,似乎默认的智能时间刻度格式化程序都在d3-scale/src/time.js
内的私有函数内部。它看起来完全是接受或离开它:您可以完全按原样使用它,也可以通过将自定义函数传递给.tickFormat()
来完全替换它。
因此,您需要创建自定义函数,在d3-scale/src/time.js
calendar
导出中复制所需的逻辑,尤其是嵌套的function tickFormat(date)
。
在我的情况下,它的一个重要部分是将时间戳0格式化为返回0的特殊情况,而不是1970年第一毫秒的最广泛描述。所以我的功能基本上是:
xAxis.tickFormat((date) => {
// If this describes 0 milliseconds from the Epoch, return '0'
if (d3.timeFormat('%Q')(date) === '0') return '0'
// Then copy and paste as many lines as needed from `d3-scale/src/time.js`
// from the `function tickFormat` adding the definitions of the formatters
// like `formatMillisecond` etc from the `calendar` scope
})
我试图找到一种方法来提取默认的刻度格式化程序,这样我就可以执行0检查然后使用默认值而不重复任何内容,但是我找不到任何方法来访问它。
除了D3源代码之外,还有D3中条件时间格式的演示:https://bl.ocks.org/wboykinm/34627426d84f3242e0e6ecb2339e9065
答案 1 :(得分:1)
您可以在轴上使用.tickFormat()和格式化函数,如下所示:
function multiFormat(date) {
return (d3.timeSecond(date) < date ? formatMillisecond
: d3.timeMinute(date) < date ? formatSecond
: d3.timeHour(date) < date ? formatMinute
: d3.timeDay(date) < date ? formatHour
: d3.timeMonth(date) < date ? (d3.timeWeek(date) < date ? formatDay :
formatWeek)
: d3.timeYear(date) < date ? formatMonth
: formatYear)(date);
}
将“formatSomething”替换为格式化d3.timeFormat(“x”)。您可以在https://bl.ocks.org/zanarmstrong/raw/ca0adb7e426c12c06a95/找到示例。
这是默认值,所以如果你想保持默认行为,你可以复制thos并改变年份:
%Y - for year boundaries, such as "2011".
%B - for month boundaries, such as "February".
%b %d - for week boundaries, such as "Feb 06".
%a %d - for day boundaries, such as "Mon 07".
%I %p - for hour boundaries, such as "01 AM".
%I:%M - for minute boundaries, such as "01:23".
:%S - for second boundaries, such as ":45".
.%L - milliseconds for all other times, such as ".012".