I'm animating rotations of groups of SVG elements using d3.js. However, I want to preserve the orientation of some elements. For example, in this fiddle (code below), the blue dot is the center of the blue circle. The blue dot is displaced vertically from the black dot, which rotates around the yellow center. I want to maintain the vertical relationship between these two dots.
In the fiddle, I maintain the vertical orientation by rotating the "shift" <g>
group backwards the same amount that its enclosing group is rotating forwards. This is the same method given in cmonkey's answer here. That works, but I'm wondering whether there are other methods. Is there any way to preserve orientation without an inverse rotation?
Why?
The inverse rotation strategy means that one has to carefully keep the inverse rotations in sync with changes to rotations of outer groups. In full-fledged versions of this code, I use rotations within rotations (within rotations), as in this example. That means summing up all of the outer groups' rotations in order to determine what the inverse rotation should be. I also want to add text labels to SVG elements. Since different text labels will fall within different numbers of rotation groups, each text label will need its own customized rotation if I want to keep the text upright.
Feel free to suggest more D3. I only hand-coded the SVG in these versions in order to get clarity about how I would dynamically generate the SVG with D3 in a later version.
<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
.cycle {
stroke : #000000;
fill : none;
}
.movingPointOnCycle {
stroke : #000000;
fill : #000000;
}
#pointB {
stroke : #0000FF;
fill : #0000FF;
}
#epicycle2 {
stroke : #0000FF;
}
.centerOfUniverse {
stroke : #000000;
fill : #000000;
}
.sun {
stroke : #000000;
fill : #F0F000;
}
.mars {
stroke : #000000;
fill : #A00000;
}
.earth {
stroke : #000000;
fill : #00A000;
}
</style>
</head>
<body>
<svg width="400" height="400">
<g transform="translate(200,200) scale(1.3)">
<circle class="sun" r="10"></circle>
<g class="cycle"speed="0.01">
<circle id="deferent" class="cycle" r="60"></circle>
<g class="epicycleCenter" transform="translate(60,0)">
<circle id="pointD" class="movingPointOnCycle" r="2"></circle>
<g class="shift" speed="-0.01" displacement="-25">
<circle id="pointB" class="movingPointOnCycle" r="2"></circle>
<line x1="0" y1="0" x2="0" y2="25" stroke-dasharray="1,2"></line>
<g class="cycle"speed="0.01">
<circle id="epicycle2" class="cycle" r="75"></circle>
</g>
</g>
</g>
</g>
</g>
</svg>
<script type="text/javascript">
var t0 = Date.now();
var svg = d3.select("svg");
d3.timer(function() {
var delta = (Date.now() - t0);
svg.selectAll(".cycle").attr("transform", function(d) {
return "rotate(" + delta * d3.select(this).attr("speed") + ")";
});
svg.selectAll(".shift").attr("transform", function(d) {
return "rotate(" + delta * d3.select(this).attr("speed") + ")"
+
"translate(0," + d3.select(this).attr("displacement") + ")"
;
});
});
</script>
</body>
</html>