|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
body { |
|
background: #07E386; |
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; |
|
/*width: 960px; |
|
height: 500px;*/ |
|
position: relative; |
|
} |
|
|
|
form { |
|
display: none; |
|
position: absolute; |
|
top: 1em; |
|
left: 1em; |
|
} |
|
|
|
path { |
|
fill: #218799; |
|
stroke: #0F6F77; |
|
stroke-width: 2px; |
|
} |
|
|
|
</style> |
|
<form> |
|
<input type="radio" name="reference" id="ref-annulus"> |
|
<label for="ref-annulus">Annulus</label><br> |
|
<input type="radio" name="reference" id="ref-planet" checked> |
|
<label for="ref-planet">Planets</label><br> |
|
<input type="radio" name="reference" id="ref-sun"> |
|
<label for="ref-sun">Sun</label> |
|
</form> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script> |
|
|
|
var width = 960, |
|
height = 500, |
|
radius = 100; |
|
|
|
var teeth = 16; |
|
var offset = 0, |
|
speed = 4, |
|
start = Date.now(); |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("viewBox", "0 0 " + width + " " + height) |
|
.append("g") |
|
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(.5)") |
|
.append("g"); |
|
|
|
var frame = svg.append("g") |
|
.datum({radius: Infinity}); |
|
|
|
frame.append("circle") |
|
//.attr("fill", "#09DD83") |
|
.attr("opacity", "0.5") |
|
.attr("r", 5); |
|
frame.append("circle") |
|
.attr("opacity", "0.5") |
|
.attr("fill", "transparent") |
|
.attr("stroke", "black") |
|
//.attr("stroke", "#09DD83") |
|
.attr("stroke-width", "4px") |
|
.attr("r", 10); |
|
|
|
var planetCount = 8; |
|
for(var i=0; i < planetCount; i++) { |
|
var x = Math.cos( (i/planetCount) * Math.PI * 2 ); |
|
var y = Math.sin( (i/planetCount) * Math.PI * 2 ); |
|
|
|
frame.append("g") |
|
.attr("class", "planet") |
|
.attr("transform", |
|
"translate(" + radius * 3 * x + "," + radius * 3 * y + ")" + |
|
", rotate(" + i * 360 / planetCount + ")" ) |
|
.datum({ |
|
teeth: teeth, |
|
radius: radius * 3 * Math.sin(Math.PI/planetCount) * (i%2 * 2 - 1) |
|
}) |
|
.append("path") |
|
.attr("d", gear); |
|
} |
|
|
|
d3.selectAll("input[name=reference]") |
|
.data([radius * 5, Infinity, -radius]) |
|
.on("change", function(radius1) { |
|
var radius0 = frame.datum().radius; |
|
var angle = (Date.now() - start) * speed; |
|
frame.datum({radius: radius1}); |
|
svg.attr("transform", "rotate(" + (offset += angle / radius0 - angle / radius1) + ")"); |
|
}); |
|
|
|
d3.selectAll("input[name=speed]") |
|
.on("change", function() { speed = +this.value; }); |
|
|
|
function gear(d) { |
|
var n = d.teeth, |
|
r2 = Math.abs(d.radius), |
|
r0 = r2 - 8, |
|
r1 = r2 + 8, |
|
r3 = d.annulus ? (r3 = r0, r0 = r1, r1 = r3, r2 + 20) : 20, |
|
da = Math.PI / n, |
|
a0 = -Math.PI / 2 + (d.annulus ? Math.PI / n : 0), |
|
i = -1, |
|
path = ["M", r0 * Math.cos(a0), ",", r0 * Math.sin(a0)]; |
|
while (++i < n) path.push( |
|
"A", r0, ",", r0, " 0 0,1 ", r0 * Math.cos(a0 += da), ",", r0 * Math.sin(a0), |
|
"L", r2 * Math.cos(a0), ",", r2 * Math.sin(a0), |
|
"L", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0), |
|
"A", r1, ",", r1, " 0 0,1 ", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0), |
|
"L", r2 * Math.cos(a0 += da / 3), ",", r2 * Math.sin(a0), |
|
"L", r0 * Math.cos(a0), ",", r0 * Math.sin(a0)); |
|
//path.push("M0,", -r3, "A", r3, ",", r3, " 0 0,0 0,", r3, "A", r3, ",", r3, " 0 0,0 0,", -r3, "Z"); |
|
return path.join(""); |
|
} |
|
|
|
d3.timer(function() { |
|
var angle = (Date.now() - start) * speed; |
|
var transform = function(d) { return "rotate(" + angle / d.radius + ")"; }; |
|
frame.selectAll("path").attr("transform", transform); |
|
frame.attr("transform", transform); // frame of reference |
|
}); |
|
|
|
</script> |