另一个答案建议使用 d3-scaleTime 的正确方法。我想深入了解您看到问题的原因,然后使用 d3-scaleTime 提供解决方案的详细信息。
序数音阶
d3.scalePoint 是一个序数比例。域表示一组离散和不连续的值。域到范围的映射基于指定域值的顺序。域中的第一个值映射到范围中的第一个值(使用 d3.scalePoint),无论其值与域中的其他值相比如何。
因此,只有存在于域中的值才能映射到范围:域中的值之间没有语义/数量关系,允许在值之间进行插值。因为您使用的是定量数据而不是定性或有序数据,所以您希望使用将域视为连续的尺度。
在某些情况下,您可能希望将 d3.scalePoint/Band 比例与基于时间的数据一起使用,但在这些情况下,您需要能够构建一个包含所有需要的值的完整域被绘制。
您的比例一开始似乎将您的数据绘制为连续的,这是巧合,如果您的中间域值是“07:00”、“六月”或“昨天”,它会出现在您范围的中间.您选择“12:00”隐藏了这样一个事实,即刻度不是根据它的值定位它,而是仅仅根据它的索引来定位它。
连续音阶
d3.scaleTime 是 d3 的连续刻度之一
连续尺度将连续的定量输入域映射到连续的输出范围。 (docs)
域和范围
对于 d3 的连续尺度,domain 和 range 必须包含相同数量的元素 - 如果每个元素中有两个以上,则 domain 和 range 被拆分为段:
.domain([a,b,c]) // where a,b,c are quantitative
.range([1,2,3])
a 和 b 之间的值将在 1 和 2 之间进行插值,同样,b 和 c 之间的值将在 2 和 3 之间进行插值。如果 domain 和 range 具有不同数量的元素,D3 将跳过一个多余的值还有更多。
在您的情况下,似乎只有两个域值就足够了,即您想要传递给秤的最小值和最大值。
使用日期
d3.scaleTime 的域需要设置日期对象而不是字符串,例如 '12:00',此外,在将值传递给比例 (scale(x)) 时,我们需要传递一个日期对象。我们可以创建一个基本的 d3 日期解析器:
d3.parseTime("%H:%M")
这给了我们:
const currentData = ['06:00', '12:00', '18:00'];
const parse = d3.timeParse("%H:%M")
const x = d3.scaleTime()
.range([0,100])
.domain(d3.extent(currentData, (time) => parse(time)))
console.log("15:00 scales to: ", x(parse('15:00')))
console.log("06:00 scales to: ", x(parse('06:00')))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
这应该像以前一样映射您的域,但也允许您绘制不在初始数据集中的值,并根据它们的值将它们正确映射到范围。