D3 Y Axis Scaling and Path Transition

南楼画角 提交于 2020-07-20 13:35:12

问题


I've been very closely following this post about D3 line transitions, implementing something similar to this, except having axis transitions by time.

The end goal is to display real time data points.

I have defined axes, like so:

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));

And the line like so:

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); });

I'm adding a transition function like the linked post talks about to transition the points horizontally over time:

(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);
})();

So far, things work great when the Y axis domain is fixed. I wanted to dynamically resize the domain and labeling of the Y axis, so I added the following to the transition function:

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

And, while the y axis scale seems to adjust correctly, there's this noticeable glitch effect when the line is redrawn every time the transition function is recalled (not between each transition function tick):

Obviously, the problem is that I'm not animating the vertical movement of the line between phases. So, the first question is: is there an easy way in D3 to do this?

I realize that setting the domain based on the max and min of the data presents a challenge because no longer is the data consistently transitioning, it is also scaling.

So I think I'll probably end of having to settle with setting the domain like so:

y.domain([temperature - 10, temperature + 10]);

Where the window is fixed. Then I think I will have to alter the transition so that it has attribute:

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

I can see that this transform will call the associated y function on line, but I'm not sure how I should redefine it. I tried:

.y(function(d, i) { return y(d / i); });

But that doesn't seem to work.

How can I get these line transitions working? Thanks so much for your help and I apologize for such an in-depth and lengthy question.

Link to full gist of code.


回答1:


EDIT: I realized my old methodology was incorrect in many cases, and removed the sample code/calculations. I'll update when I'm able to figure out what went wrong...

This is a cool problem. The example that you link to (Mike Bostock's) is simply interpolating a translation in the X direction to smoothly shift the curve to the left as it is updated. However, in your example, you also want to change the Y axis scale in real time --

If we think about this, it means that in addition to shifting the curve to the left (via translate transformation in the X direction), we also need to squish it down a little bit (via scale transformation in the Y direction). In addition to scaling it in the Y direction, it will also need to be translated a bit to make up for the new position of the y axis.

You can do all of this with the [SVG Matrix transformation][1]. You just need to figure out what your constants are (a,b,c,d,e,f). These can be calculated using your old and new scales.



来源:https://stackoverflow.com/questions/39907182/d3-y-axis-scaling-and-path-transition

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!