0

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>
Community
  • 1
  • 1
Mars
  • 8,689
  • 2
  • 42
  • 70
  • For [simple rotation](http://stackoverflow.com/questions/25089341/how-to-keep-text-orientation-unchanged-during-rotation-in-svg/25097447#25097447), use `sin()` and `cos()` functions and move the text to that position. The math can be expanded to double rotation, however my example is hand coded (not D3). – Alvin K. Sep 25 '14 at 06:17
  • Thanks @AlvinK. That's an alternative. It sounds like a good solution without using D3. I think it's equivalent to using SVG `rotate` functions. What I'd really like is some way to say "go ahead and rotate this object's location, but keep it in its own little world that preserves its original orientation." That way I wouldn't have to keep track of and sum up different rotation constants, as I do in [this example](http://members.logical.net/~marshall/copernicanishExperiment.html). – Mars Sep 25 '14 at 14:57
  • Analogy: 3 or more gears are connected in series and first gear rotates. Pick a tooth on last gear and attach label. You need this label to be upright, regardless of rotation. In real world, I'd attach a weight to the label so gravity will pull it upright. Can anyone code a SVG equivalent? – Alvin K. Sep 25 '14 at 19:33
  • Nice analogy. I had started wondering whether some trick could be done with a d3.js force layout. It's possible to anchor the layout, and I think there are probably parameter settings that could cause one point attached to a label to be pulled up (or down--whatever) without causing the label to bounce around as the graphic rotates. Bounce would be distracting. It would be slightly unsatisfying to use this trick to orient something in which more rotation is occurring (one goal), but if it works .... – Mars Sep 25 '14 at 19:58
  • Hmm. Or maybe take a point that's independent of the rotating objects, and let the label calculate its relationship to that point. Then use that to determine how much rotation must be "undone" in order to keep the label (or whatever it is) upright. This is where the trig functions would come in handy, and this strategy avoids keeping track of all of the intervening rotations, yet seems cleaner than using a force layout. – Mars Sep 25 '14 at 20:06

0 Answers0