分形螺旋图:javascript 中可能存在舍入误差
Fractal Spirographs: possible rounding errors in javascript
我一直在尝试复制 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 中的示例。下面是完整代码。
// 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)
有趣的可视化。
这不是对您问题的直接回答,因为我发现您的代码过于混乱且难以调试。您似乎做的数学比您需要的多得多;来回转换到不同的坐标系。此外,在 setTimeout
中设置动画也不是一个好的做法。
这是一个利用 d3.transition
并简化计算的快速重构。也通过数据带动新圈子的加入。
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@4.0.0" 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>
只需在此处删除 cy +.03
的角度偏移:
attr("cy",function(d){
// assigning new center y-coordinate
return polarToCoordinate(interval.r,interval.theta +.03,
我一直在尝试复制 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 中的示例。下面是完整代码。
// 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)
有趣的可视化。
这不是对您问题的直接回答,因为我发现您的代码过于混乱且难以调试。您似乎做的数学比您需要的多得多;来回转换到不同的坐标系。此外,在 setTimeout
中设置动画也不是一个好的做法。
这是一个利用 d3.transition
并简化计算的快速重构。也通过数据带动新圈子的加入。
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@4.0.0" 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>
只需在此处删除 cy +.03
的角度偏移:
attr("cy",function(d){
// assigning new center y-coordinate
return polarToCoordinate(interval.r,interval.theta +.03,