Keeping text horizontal while it's position is

2019-08-04 08:52发布

问题:

I'm trying to add labels to the planets around the sun into this example : http://bl.ocks.org/djvanderlaan/4953593. So far, I've managed to add the labels, but the orientation of the labels is rotating with their position, while I want to keep them horizontal for the comfort of the readers. I've been finding a beginning of a solution to my problem here : how to keep text orientation unchanged during rotation in SVG but it's seems very complicated to me (I am a newbie and really not good at trigonometry) and plus, it's not using d3.js. Here is the code that I'am using :

<div id="planetarium">
</div>

<script type="text/javascript">
  var w = 800, h = 600;
  var t0 = Date.now();

  var planets = [
    { R: 300, r:  5, speed: 5, phi0: 90, name : 'Mercure'},
    { R: 150, r: 10, speed: 2, phi0: 190, name : 'Saturne'}
  ];


  var svg = d3.select("#planetarium").insert("svg")
    .attr("width", w).attr("height", h);

  svg.append("circle").attr("r", 20).attr("cx", w/2)
    .attr("cy", h/2).attr("class", "sun")

  var container = svg.append("g")
    .attr("transform", "translate(" + w/2 + "," + h/2 + ")")


  container.selectAll("g.planet").data(planets).enter().append("g")
    .attr("class", "planet").each(function(d, i) {
      var orbit = d3.select(this).append("circle").attr("class", "orbit")
        .attr("r", d.R);
      var planet = d3.select(this).append("circle").attr("r", d.r).attr("cx",d.R)
        .attr("cy", 0).attr("class", "planet");
      var text = d3.select(this).append("text")
        .attr("x", d.R)
        .attr("y", ".31em")
        .text(function(d) { return d.name; });


  d3.timer(function() {
    var delta = (Date.now() - t0);
    planet.attr("transform", function(d) {
      return "rotate(" + d.phi0 + delta * d.speed/200 + ")";
    });
    text.attr("transform", function(d) {
      return "rotate(" + d.phi0 + delta * d.speed/200 + ")";
    });
  });
 });

</script>

Here is my plunkr : http://plnkr.co/edit/dJEVXIeR7ly536tcMPWt?p=preview Thank you very much for your help !

回答1:

I've finally found a solution inspired by this example : D3.js: rotate group, keep text the same orientation? Instead of making two different variables for planets and text, I've gathered them in a same rotating group, and then added an inverse rotation on the text, but centered on the planet's center rather than the center of the container. Then I set both phi0 (the positions of the planets at the beginning of the animation) to 0, so that the text would be frozen horizontally. Here is my code :

var planets = [
    { R: 300, r:  5, speed: 5, phi0: 0, name : 'Mercure'},
    { R: 150, r: 10, speed: 2, phi0: 0, name : 'Saturne'}
  ];
//... 
var container = svg.append("g")
    .attr("transform", "translate(" + w/2 + "," + h/2 + ")")

  var orbit = container.selectAll(".orbit")
                       .data(planets)
                       .enter()
                       .append("circle")
                       .attr("class", "orbit")
                       .attr("r", function(d) {return d.R;});
  var planets = container.selectAll(".planet")
                       .data(planets)
                       .enter()
                       .append("g")

    planets.append("circle")
                       .attr("class", "planet")
                       .attr("r", function(d) {return d.r;})
                       .attr("cx", function(d) {return d.R; })
                       .attr("cy", 0);


    planets.append("text")
                       .attr("dx", function(d) {return d.R;})
                       .attr("dy", ".35em")
                       .text(function(d) {return d.name});


  d3.timer(function() {
    var delta = (Date.now() - t0);
    planets.attr("transform", function(d) {
      return "rotate(" + d.phi0 + delta * d.speed/200 + ")";
    });
    planets.selectAll("text").attr("transform", function(d) {
      return "rotate(" + -1*(d.phi0 + delta * d.speed/200) + " " + d.R + " " + 0 + ")";
    });
  });

Not sure this is a very good solution, but for the moment it works. I will learn trigonometry though, I promise ;)