简体   繁体   中英

d3 steady horizontal transition along an SVG path

I'm using a d3 attrTween to translate a circle over a path smoothly, similar to this example and as shown in the picture below:

图形

The circle's transition is defined here:

function transition() {
    circle.transition()
    .duration(2051)
    .ease("linear")
    .attrTween("transform", translateAlong(path.node()))
}

And the attribute tween is shown here:

function translateAlong(path) {
    var l = path.getTotalLength();
    return function (d, i, a) {
        return function (t) {
            var p = path.getPointAtLength(t * l);
            return "translate(" + p.x + "," + p.y + ")";
        };
    };
}

This works well thanks to the SVG method getPointAtLength , which allows us to retrieve coordinates at different lengths of the path. However, I need a different kind of behavior and I've been unable to come up with a solution so far.

I need the circle to animate along the path, but at a steady horizontal speed. Meaning that the circle ought to take as much time to navigate this slice:

slice1

As it does with this slice:

slice2

Because both slices encompass the same width. On a low level, what I need is to be able to translate any X coordinate with its corresponding Y coordinate along the path . I've looked at all the SVG path methods and I haven't found anything particularly useful here. I'm hoping there's some way in D3 to feed an X coordinate to a d3 line and retrieve its corresponding Y coordinate.

Here's a JSFiddle working as described above. I'd really appreciate any help I can get on this. Thanks!

I ended up creating a lookup array for all my points along the line using getPointAtLength :

var lookup = [];
var granularity = 1000;
var l = path.node().getTotalLength();
for(var i = 1; i <= granularity; i++) {
    var p = path.node().getPointAtLength(l * (i/granularity))
    lookup.push({
        x: p.x,
        y: p.y
    })
}

Once I had all those points in my lookup table, I used a bisector in my translate tween:

var xBisect = d3.bisector(function(d) { return d.x; }).left;
function translateAlong(path) {
    var l = path.getTotalLength();
    return function (d, i, a) {
        return function (t) {
            var index = xBisect(lookup, l * t);
            var p = lookup[index];
            return "translate(" + p.x + "," + p.y + ")";
        };
    };
}

And it works as expected! Yahoo!

Fiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM