我正在使用具有滑动x轴的d3实现图表。 Demo
问题是,当我换到另一个标签,然后返回(比如10秒后),d3似乎试图重放丢失的过渡,这导致轴的非常尴尬的行为。请参阅here。
迈克博斯托克mentions that:D3 4.0通过更改时间定义来解决此问题。转换通常不需要与绝对时间同步;转换主要是用于跨视图跟踪对象的感知辅助工具。因此,D3 4.0在感知时间上运行,仅在页面位于前景时才进行。当一个标签背景并返回到前台时,它就会发现它没有发生任何事情。
这真的是固定的吗?我做错了吗?
const timeWindow = 10000;
const transitionDuration = 3000;
const xScaleDomain = (now = new Date()) =>
[now - timeWindow, now];
const totalWidth = 500;
const totalHeight = 200;
const margin = {
top: 30,
right: 50,
bottom: 30,
left: 50
};
const width = totalWidth - margin.left - margin.right;
const height = totalHeight - margin.top - margin.bottom;
const svg = d3.select('.chart')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
svg
.append('rect')
.attr('width', width)
.attr('height', height);
// Add x axis
const xScale = d3.scaleTime()
.domain(xScaleDomain(new Date() - transitionDuration))
.range([0, width]);
const xAxis = d3.axisBottom(xScale);
const xAxisSelection = svg
.append('g')
.attr('transform', `translate(0, ${height})`)
.call(xAxis);
// Animate
const animate = () => {
xScale.domain(xScaleDomain());
xAxisSelection
.transition()
.duration(transitionDuration)
.ease(d3.easeLinear)
.call(xAxis)
.on('end', animate);
};
animate();
svg {
margin: 30px;
background-color: #ccc;
}
rect {
fill: #fff;
outline: 1px dashed #ddd;
}
<script src="https://unpkg.com/d3@4.4.1/build/d3.js"></script>
<div class="chart"></div>
答案 0 :(得分:1)
问题不在于D3过渡。这里的问题是new Date()
。
每次转到另一个标签页时,转换都会暂停。到现在为止还挺好。但是当你回到图表时,让我们说,在20秒之后,你得到一个新的日期,即当前日期......但是你的timeWindow
和你的transitionDuration
是一样的:< / p>
const timeWindow = 10000;
const transitionDuration = 3000;
const xScaleDomain = (now = new Date()) => [now - timeWindow, now];
这使得轴向前跳得更快,因为域中任何一点的旧值和新值之间的差异不再是3秒。
这是一个非常简单的解决方案,太粗糙,需要改进,只是为了向您展示问题是new Date()
。在这个解决方案中(再次,远非完美),我手动设置每个动画中的日期跳跃10秒,无论你停留在另一个标签中多久:
var t = xScale.domain()[1];
t.setSeconds(t.getSeconds() + 10);
xScale.domain([xScale.domain()[1], t]);
以下是CodePen:http://codepen.io/anon/pen/GrjMxy?editors=0010
使用您的代码的更好的解决方案是更改timeWindow
和transitionDuration
以考虑新new Date()
和旧new Date()
之间的差异(即,用户在另一个标签中的时间长度。)