Reputation: 1069
Using d3 I am attempting to create an animation between two lines that have a different number of data points.
I have referenced Mike Bostock's post: https://bl.ocks.org/mbostock/3916621 which contains a pathTween method for two paths described in "M0..." format.
The data I am trying to plot is raw data points. For instance:
var line = d3.svg.line().interpolate("monotone")
.x(function(d){ return d.x; })
.y(function(d){ return d.y; });
low_res = [
{x: 0 , y: 4 },
{x: 5 , y: 14 },
{x: 10 , y: 11 },
{x: 85 , y: 14 },
{x: 90 , y: 11 },
{x: 95 , y: 7 },
{x: 100 , y: 4 },
];
var high_res = [[
{x: 0 , y: 4 },
{x: 1 , y: 12 },
{x: 2 , y: 11 },
{x: 3 , y: 11 },
{x: 4 , y: 14 },
{x: 5 , y: 14 },
{x: 6 , y: 12 },
{x: 7 , y: 4 },
{x: 8 , y: 3 },
{x: 9 , y: 1 },
{x: 10 , y: 11 },
{x: 11 , y: 11 },
{x: 12 , y: 1 },
{x: 13 , y: 13 },
{x: 14 , y: 1 },
{x: 15 , y: 5 },
{x: 16 , y: 13 },
{x: 17 , y: 10 },
]]
var lines = svg.selectAll(".line").data(high_res)
.enter()
.append("path")
.attr("class","line")
.attr("d", line)
.style("stroke", "blue");
This works find for displaying the high_res plot. Mike Bostock's example is as follows:
var d0 = "M0,0c100,0 0,100 100,100c100,0 0,-100 100,-100",
d1 = "M0,0c100,0 0,100 100,100c100,0 0,-100 100,-100c100,0 0,100 100,100";
svg.append("path")
.attr("transform", "translate(180,150)scale(2,2)")
.attr("d", d0)
.call(transition, d0, d1);
function transition(path, d0, d1) {
path.transition()
.duration(2000)
.attrTween("d", pathTween(d1, 4))
.each("end", function() { d3.select(this).call(transition, d1, d0); });
}
function pathTween(d1, precision) {
return function() {
var path0 = this,
path1 = path0.cloneNode(),
n0 = path0.getTotalLength(),
n1 = (path1.setAttribute("d", d1), path1).getTotalLength();
// Uniform sampling of distance based on specified precision.
var distances = [0], i = 0, dt = precision / Math.max(n0, n1);
while ((i += dt) < 1) distances.push(i);
distances.push(1);
// Compute point-interpolators at each distance.
var points = distances.map(function(t) {
var p0 = path0.getPointAtLength(t * n0),
p1 = path1.getPointAtLength(t * n1);
return d3.interpolate([p0.x, p0.y], [p1.x, p1.y]);
});
return function(t) {
return t < 1 ? "M" + points.map(function(p) { return p(t); }).join("L") : d1;
};
};
}
I am struggling to figure out how to create a native path object, such as d0, d1 in the second example from my set of raw data which can be passed into the transition function ie:
.call(transition, d0, d1);
Many thanks in advance for any advice.
Upvotes: 2
Views: 163
Reputation: 108567
Your question seems to boil down to:
How can I generate a path for my datapoints?
This is actually what the line function is doing. It's as simple as:
var low_res = [
{x: 0 , y: 4 },
{x: 5 , y: 14 },
{x: 10 , y: 11 },
{x: 85 , y: 14 },
{x: 90 , y: 11 },
{x: 95 , y: 7 },
{x: 100 , y: 4 },
],
high_res = [
{x: 0 , y: 4 },
{x: 1 , y: 12 },
{x: 2 , y: 11 },
{x: 3 , y: 11 },
{x: 4 , y: 14 },
{x: 5 , y: 14 },
{x: 6 , y: 12 },
{x: 7 , y: 4 },
{x: 8 , y: 3 },
{x: 9 , y: 1 },
{x: 10 , y: 11 },
{x: 11 , y: 11 },
{x: 12 , y: 1 },
{x: 13 , y: 13 },
{x: 14 , y: 1 },
{x: 15 , y: 5 },
{x: 16 , y: 13 },
{x: 17 , y: 10 },
];
var line = d3.svg.line().interpolate("monotone")
.x(function(d){ return d.x; })
.y(function(d){ return d.y; });
var d0 = line(low_res),
d1 = line(high_res);
console.log(d0);
console.log(d1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 1