patternjavascriptMinor
D3.js interpolating line on circumference of circle
Viewed 0 times
circumferencecircleinterpolatingline
Problem
For now, I've tried to make a line rotate on the path of a circle, but used
I would like your thoughts before I add two more circles just like in this webpage.
`
setInterval multiple times and there might be other ways of achieving the same.I would like your thoughts before I add two more circles just like in this webpage.
var width = 300;
var height = 300;
var body = d3.select("body")
var svg = body.append("svg")
.attr("width",width)
.attr("height",height)
.attr("fill","blue")
var rad = Math.PI;
var circlePath = svg.append("path")
.attr('d', "M70,100a30,30 0 1,0 60,0a30,30 0 1,0 -60,0")
.attr('fill', 'none')
.attr('stroke', 'steelblue' )
// var path =
console.warn(circlePath.node());
var path1 = circlePath.node();
var myLine = svg.append('line')
.attr('x1', 100)
.attr('y1', 100)
.attr('x2', function(){return path1.getPointAtLength(l).x})
.attr('y2', function(){return path1.getPointAtLength(l).y} )
.attr('stroke', "red" )
.attr('stroke-width',3)
var l = 1
setInterval(function(){
myLine.transition()
.duration(20)
.attr('stroke', "blue")
.attr('x2', function(){return path1.getPointAtLength(l).x})
.attr('y2', function(){return path1.getPointAtLength(l).y})
.each("end", endAnimationfunc)
}, 5);
setInterval(function(){
if(l
`
Solution
I'd suggest using nested group elements (`
var height = 200;
var body = d3.select("body");
var svg = body.append("svg")
.attr("width", width)
.attr("height", height)
.attr("fill", "blue");
function addCircle(container, radius, x, y) {
// Note the hardcoded rotation; it's just an example
var group = container.append("g")
.attr("class", "circle-container")
.attr("transform", "translate(" + x + ", " + y + ")");
function rotate() {
group.transition()
.duration(10000)
.ease("linear")
.attrTween("transform", function (d, i, a) {
return function (t) {
var rotation = t * 360;
return "translate(" + x + ", " + y + ") rotate(" + String(rotation) + ")";
};
})
.each("end", rotate);
};
rotate();
group.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", radius)
.style("fill", "none")
.style("stroke", "steelblue");
group.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", radius)
.attr("y2", 0)
.style("stroke", "steelblue");
return group;
}
var c1 = addCircle(svg, 30, width/2, height/2); // centered
var c2 = addCircle(c1, 20, 30, 0); // offset by 1st circle's radius
var c3 = addCircle(c2, 15, 20, 0); // offset by 2nd circle's radius
s) with transform attributes.
I.e. draw the circle (just as a element) and the line inside a group, and then draw a nested group with a circle and line within that, and so on. When you rotate the outermost group, the nested ones will follow. Rotate each of them, and you'll get the effect from the demo.
This way, you only need to animate one thing: rotation. For instance:
var width = 200;var height = 200;
var body = d3.select("body");
var svg = body.append("svg")
.attr("width", width)
.attr("height", height)
.attr("fill", "blue");
function addCircle(container, radius, x, y) {
// Note the hardcoded rotation; it's just an example
var group = container.append("g")
.attr("class", "circle-container")
.attr("transform", "translate(" + x + ", " + y + ")");
function rotate() {
group.transition()
.duration(10000)
.ease("linear")
.attrTween("transform", function (d, i, a) {
return function (t) {
var rotation = t * 360;
return "translate(" + x + ", " + y + ") rotate(" + String(rotation) + ")";
};
})
.each("end", rotate);
};
rotate();
group.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", radius)
.style("fill", "none")
.style("stroke", "steelblue");
group.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", radius)
.attr("y2", 0)
.style("stroke", "steelblue");
return group;
}
var c1 = addCircle(svg, 30, width/2, height/2); // centered
var c2 = addCircle(c1, 20, 30, 0); // offset by 1st circle's radius
var c3 = addCircle(c2, 15, 20, 0); // offset by 2nd circle's radius
Heck, you can do this in pure SVG (added extra groups to isolate rotation):
At any rate, you can simply skip all the getPointAtLength calls. Your path is a circle, so a) you can use a element, and b) any point on its circumference can be described using some simple math:
var x = Math.cos(t) * radius + centerX;
var y = Math.sin(t) * radius + centerY;
where t is something between 0 and 2π (or beyond that; it'll just loop around). So your animation needs only change the value of t` to find a point on the circle.Code Snippets
var x = Math.cos(t) * radius + centerX;
var y = Math.sin(t) * radius + centerY;Context
StackExchange Code Review Q#87636, answer score: 3
Revisions (0)
No revisions yet.