【问题标题】:How to disallow years in d3.scaleTime() axis ticks?如何在 d3.scaleTime() 轴刻度中禁止年份?
【发布时间】:2018-05-30 09:38:46
【问题描述】:

使用 D3(v4,升级到 v5 也是一种选择),我正在为时间间隔绘制时间序列。数据的持续时间未知,通常为几秒,并且我们有一个开始日期戳和一个结束日期戳。

我目前生成 x 轴的方法是这样的,其中 startTimeendTime 是数字时间戳,widthheight 是数字,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 中手动选择它并修改它的值,但我想知道是否可以这样做在 使用 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 时间格式逻辑...

【问题讨论】:

    标签: d3.js


    【解决方案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

    【讨论】:

      【解决方案2】:

      你可以在你的轴上使用 .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".
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-03
        • 2016-06-03
        • 1970-01-01
        • 2013-03-10
        • 1970-01-01
        相关资源
        最近更新 更多