D3 Y 轴缩放和路径过渡

Jam*_*lor 6 d3.js

我一直非常密切地关注这篇关于 D3 线转换的帖子,实现了与此类似的东西,除了按时间进行轴转换。

最终目标是显示实时数据点。

我已经定义了轴,如下所示:

var x = d3.time.scale()
    .domain([now - (n - 2) * duration, now - duration])
    .range([0, width]);

var y = d3.scale.linear()
    .range([height, 0])
    .domain([0, 100])

var axisx = svg.append('g')
    .attr('class', 'x axis')
    .attr('transform', `translate(0, ${height})`)
    .call(x.axis = d3.svg.axis().scale(x).orient('bottom').tickPadding(10));

var axisy = svg.append('g')
    .attr('class', 'y axis')
    .attr('transform', `translate(${width}, 0)`)
    .call(y.axis = d3.svg.axis().scale(y).orient('right').tickPadding(10));
Run Code Online (Sandbox Code Playgroud)

和这样的行:

var line = d3.svg.line()
    .interpolate('basis')
    .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
    .y(function(d, i) { return y(d); });
Run Code Online (Sandbox Code Playgroud)

我正在添加一个转换函数,就像链接的帖子所说的随着时间的推移水平转换点:

(function tick() {

    transition = transition.each(function() {

        // Update the domain of the x-axis
        now = new Date();
        x.domain([now - (n - 2) * duration, now - duration]);

        // Push the new data point
        data.push(temperature);

        // Redraw the line
        svg.select('.line')
            .attr('d', line)
            .attr('transform', null);

        // Slide the x-axis left
        axisx.call(x.axis);

        // Slide the line left
        path.transition()
            .attr('transform', `translate(${x(now - (n - 1) * duration)})`);

        // Pop the old data point off the front
        data.shift();

    }).transition().each('start', tick);
})();
Run Code Online (Sandbox Code Playgroud)

到目前为止,当 Y 轴域固定时,一切都很好。我想动态调整 Y 轴的域和标签的大小,所以我在转换函数中添加了以下内容:

y.domain([
    Math.min.apply(Math, data) - 10,
    Math.max.apply(Math, data) + 10
])
axisy.call(y.axis);
Run Code Online (Sandbox Code Playgroud)

而且,虽然 y 轴比例似乎正确调整,但每次调用转换函数时(不是在每个转换函数刻度之间)重绘线条时,都会出现这种明显的故障效果:

图表重绘故障

显然,问题在于我没有为阶段之间的线的垂直移动设置动画。那么,第一个问题是:D3 中是否有一种简单的方法可以做到这一点?

我意识到根据数据的最大值和最小值设置域是一个挑战,因为数据不再是持续转换,它也在扩展。

所以我想我可能会不得不像这样设置域:

y.domain([temperature - 10, temperature + 10]);
Run Code Online (Sandbox Code Playgroud)

窗户固定的地方。然后我想我将不得不改变过渡,使其具有属性:

.attr('transform', `translate(${x(now - (n - 1) * duration)}, ${y(data[1] - data[0]}))`);
Run Code Online (Sandbox Code Playgroud)

我可以看到这transform将在 上调用关联的y函数line,但我不确定应该如何重新定义它。我试过:

.y(function(d, i) { return y(d / i); });
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用。

我怎样才能让这些线转换工作?非常感谢您的帮助,对于如此深入而冗长的问题,我深表歉意。

链接到完整的代码要点。

Joe*_*oel 0

编辑:我意识到我的旧方法在很多情况下都是不正确的,并删除了示例代码/计算。当我能够弄清楚出了什么问题时,我会更新......

这是一个很酷的问题。您链接到的示例(Mike Bostock 的)只是在 X 方向插入平移,以便在更新时将曲线平滑地向左移动。但是,在您的示例中,您还想实时更改 Y 轴刻度 -

如果我们考虑一下这一点,这意味着除了将曲线向左移动(通过 X 方向的平移变换)之外,我们需要将其压扁一点(通过 Y 方向的缩放变换)。除了在 Y 方向上缩放之外,还需要平移一点以弥补 y 轴的新位置。

您可以使用 [SVG 矩阵变换][1] 来完成所有这些操作。你只需要弄清楚你的常数是什么(a,b,c,d,e,f)。这些可以使用您的旧秤和新秤来计算。