Reputation: 45
I have been trying to replicate the example present in the link. So I have started out with two circles, one fixed and one rotating. But the rotating circle is drifting away from the stationary circle and some times it is falling into the stationary circle. Can someone please help me fix this. I have created a live demo of code at the following link.Below shared is the complete code.
// takes two points x1,y1,x2,y2 and return r and Θ
function coordinateToPolar(x1,y1,x2,y2){
polar={}
polar.r= Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2))
polar.theta=Math.atan2(y2-y1,x2-x1)
return polar;
}
function degreeToRadians(degree){
return (degree/180)*Math.PI;
}
function radiansToDegrees(rad){
return (rad/Math.PI)*180
}
// takes one point h,k the center of circle and r and Θ
function polarToCoordinate(r,theta,h,k){
point={}
point.x=h+r*Math.cos(theta);
point.y=k+r*Math.sin(theta);
return point;
}
//circle ds
function Circle(r,h,k) {
this.r=r;
this.h=h;
this.k=k;
}
/// Adjusting the geometric center
bufferX=250;
bufferY=250;
svg=d3.select("body").append("svg");
startX=200;
startY=200;
startR=150;
dsCircles=[];
// intiating prevR and lastR to 0
prevR=0;
lastR=0;
for(i=0;i<2;i++){
currR=startR>>(i*1);
dsCircles[i]=new Circle(currR, i==0?bufferX+prevR+currR: bufferX+ prevR+lastR+currR,bufferY+startY)
lastR=currR;
prevR +=currR;
}
svg.selectAll("circles").data(dsCircles).enter().append("circle").attr("id",function(d,i){return "circle"+(i+1)}).attr("r",function(d){ return d.r}).attr("cy",function(d){return d.k}).attr("cx",function(d){ return d.h});
window.setInterval(function interval(){
// static variable initiated only once
if(interval["itr"]==undefined){
// initializing iteration counter to 0
interval.itr=0;
// getting the polar coordinates of the circles with respect to geometric center
interval.theta=coordinateToPolar(dsCircles[0].h,dsCircles[0].k,dsCircles[1].h,dsCircles[1].k).theta;
interval.r=coordinateToPolar(dsCircles[0].h,dsCircles[0].k,dsCircles[1].h,dsCircles[1].k).r;
}
d3.select("#circle2").attr("cx",function(d){
// assigning new center x-coordinate
return polarToCoordinate(interval.r,interval.theta,dsCircles[0].h,dsCircles[0].k).x;
}).attr("cy",function(d){
// assigning new center y-coordinate
return polarToCoordinate(interval.r,interval.theta +.03,dsCircles[0].h,dsCircles[0].k).y;
});
d3.select("#circle2").attr("style",function(d){ return interval.itr%2==0?"stroke:red":"stroke:blue"; })
interval.itr++;
interval.theta +=.003
},10)
Upvotes: 2
Views: 149
Reputation: 108537
Interesting visualization.
This is not a direct answer to you question because I find your code overly confusing and troubling to debug. You seem to be doing way more math then you need; converting back from forth to different coordinate systems. Also, animating in a setTimeout
is not a good practice.
Here's a quick refactor that takes advantage of d3.transition
and simplifies the calculations. It also drives the addition of new circles through data.
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var width = 500,
height = 500;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform','translate(' + width/2 + ',' + height/2 + ')');
var data = [
{
r: 75,
x: 0,
y: 0,
c: 'black',
d: 0
}, {
r: 50,
x: 0,
y: 0,
c: 'steelblue',
d: 7000
},{
r: 30,
x: 0,
y: 0,
c: 'orange',
d: 5000
},{
r: 20,
x: 0,
y: 0,
c: 'red',
d: 2000
},{
r: 10,
x: 0,
y: 0,
c: 'green',
d: 500
}
];
data.forEach(function(d,i){
if (i === 0) d.pD = null;
else d.pD = data[i-1];
});
svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('r', function(d){
return d.r;
})
.style('fill', 'none')
.style('stroke', function(d){
return d.c
})
.each(goRound);
function goRound(d,i){
if (!d.pD) return function(t) { }
var self = d3.select(this);
self.transition()
.ease(d3.easeLinear)
.duration(function(d){
return d.d;
})
.tween("go.round", function(){
var inter = d3.interpolate(0, Math.PI * 2);
return function(t) {
d.x = Math.cos(inter(t)) * (d.pD.r + d.r) + d.pD.x;
d.y = Math.sin(inter(t)) * (d.pD.r + d.r) + d.pD.y;
self.attr('cx', d.x);
self.attr('cy', d.y);
};
})
.on('end', goRound);
}
</script>
</body>
</html>
Upvotes: 1
Reputation: 80197
Just remove angle shift for cy +.03
here:
attr("cy",function(d){
// assigning new center y-coordinate
return polarToCoordinate(interval.r,interval.theta +.03,
Upvotes: 3