Reputation: 643
I want to add circles to an svg for each path created by the nest so that the circles lead the drawing of the paths. Similar to this fiddle, but with nested data.
Here is some reproducible example code in d3.v4 and a runnable snippet of the paths I would like to add circles to:
var data=[{group:1,x:6,y:8},
{group:1,x:4,y:4},
{group:1,x:1,y:2},
{group:2,x:8,y:3},
{group:2,x:1,y:6},
{group:2,x:7,y:5},
{group:3,x:7,y:1},
{group:3,x:6,y:6},
{group:3,x:3,y:2}];
var height = 600
var width = 800
var svg = d3.select("body")
.append("svg")
.attr("height", "100%")
.attr("width", "100%");
var colours = ["#0000FF",
"#FF0000",
"#00FF00"
];
var line = d3.line()
.x(function(d, i) {
return d.x * 20;
})
.y(function(d, i) {
return d.y * 20;
})
.curve(d3.curveNatural);
function tweenDash() {
var l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) {
return i(t);
};
}
function transition(selection) {
selection.each(function() {
d3.select(this).transition()
.duration(5000)
.attrTween("stroke-dasharray", tweenDash)
.ease(d3.easeLinear);
})
}
var dataGroup = d3.nest()
.key(function(d) {
return d.group;
})
.entries(data);
dataGroup.forEach(function(d, i) {
var path = svg.append("path")
.attr("d", line(d.values))
.attr("stroke", colours[i])
.attr("stroke-width", 1)
.attr("fill", "none");
transition(d3.selectAll("path"))
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
Upvotes: 0
Views: 89
Reputation: 13129
Using this example, I've added circles to your paths. Note that they do not follow the path perfectly, but this is covered by increasing their radius.
A couple of times, you use .forEach()
or .each()
to iterate over the data or the selection, but you don't need to. d3
is made to work with arrays of data at once, so you can easily apply one transformation to multiple elements, each using their own data. Getting used to that can drastically improve your developer experience.
var data = [{
group: 1,
x: 6,
y: 8
},
{
group: 1,
x: 4,
y: 4
},
{
group: 1,
x: 1,
y: 2
},
{
group: 2,
x: 8,
y: 3
},
{
group: 2,
x: 1,
y: 6
},
{
group: 2,
x: 7,
y: 5
},
{
group: 3,
x: 7,
y: 1
},
{
group: 3,
x: 6,
y: 6
},
{
group: 3,
x: 3,
y: 2
}
];
var height = 600
var width = 800
var svg = d3.select("body")
.append("svg")
.attr("height", "100%")
.attr("width", "100%");
var colours = ["#0000FF",
"#FF0000",
"#00FF00"
];
var line = d3.line()
.x(function(d, i) {
return d.x * 20;
})
.y(function(d, i) {
return d.y * 20;
})
.curve(d3.curveNatural);
function tweenDash() {
var l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) {
return i(t);
};
}
function tweenCircle(i, paths) {
var path = paths
.filter(function(_, j) { return i === j; })
.node();
var l = path.getTotalLength();
return function(t) {
var p = path.getPointAtLength(t * l);
return "translate(" + [p.x, p.y] + ")";
};
}
function transition(path, circle) {
path.transition()
.duration(2000)
.attrTween("stroke-dasharray", tweenDash)
.ease(d3.easeLinear);
circle.transition()
.duration(2000)
.attrTween("transform", function(d, i) { return tweenCircle(i, path); })
.ease(d3.easeLinear);
}
var dataGroup = d3.nest()
.key(function(d) {
return d.group;
})
.entries(data);
var path = svg.selectAll('path')
.data(dataGroup)
.enter()
.append("path")
.attr("d", function(d) { return line(d.values); })
.attr("stroke", function(d, i) { return colours[i]; })
.attr("stroke-width", 1)
.attr("fill", "none");
var circle = svg.selectAll('circle')
.data(dataGroup)
.enter()
.append("circle")
.attr("fill", function(d, i) { return colours[i]; })
.attr("transform", function(d) {
const start = d.values[0];
return "translate(" + [start.x, start.y] + ")"; })
.attr("r", 8);
transition(path, circle);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
Upvotes: 1