Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
631 views
in Technique[技术] by (71.8m points)

javascript - D3.js rotate axis labels around the middle point

I am working with D3.js now and even though I found very similar cases I am not really able to put them together and move on.

I have something similar as a radar chart and I would like to append to each ax I create (number of axes is not fixed could be 4, but also 40) text, which I already have, but rotate the text around center point and turn them as soon as they reach 180 degrees, actually 0 degrees.

The result should look like this:

enter image description here

What I have now is this:

enter image description here

I only know how to reach this within arc, which is also nicely shown here, but I did not really figure it out for my case.

This is my code snippet, where I append those text criteria:

//Write criterias
      axis.append("text")
        .attr("class","labels")
        .attr("font-size","12px")
        .attr("font-family","Montserrat")
        .attr("text-anchor","middle") 
        .attr("fill","white")
        .attr("x",function (d, i) {
          return radius * Math.cos(angleSlice * i - Math.PI/2)*options.circles.labelFactor;
        })
        .attr("y",function (d, i) {
          return radius * Math.sin(angleSlice * i - Math.PI/2)*options.circles.labelFactor;
        })
        .text(function (d) {
          return d;
        });

EDIT:

Here is my fiddle: https://jsfiddle.net/fsb47ndf/

Thank you for any advise

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Some people find it difficult to rotate an SVG element, because the rotate function of the transform attribute rotates the element around the origin (0,0), not around its center:

If optional parameters and are not supplied, the rotate is about the origin of the current user coordinate system (source)

Thus, an easy option is dropping the x and the y attributes of the texts, and positioning them using transform. That way, we can easily calculate the rotation:

.attr("transform", function(d, i) {
    var rotate = angleSlice * i > Math.PI / 2 ?
        (angleSlice * i * 180 / Math.PI) - 270 :
        (angleSlice * i * 180 / Math.PI) - 90;
    return "translate(" + radius * Math.cos(angleSlice * i - Math.PI / 2) * options.circles.labelFactor +
        "," + radius * Math.sin(angleSlice * i - Math.PI / 2) * options.circles.labelFactor +
        ") rotate(" + rotate + ")"
})

Here is your code:

data = [{
   name: 'DATA1',
   value: 22,
 }, {
   name: 'DATA2',
   value: 50,
 }, {
   name: 'DATA3',
   value: 0,
 }, {
   name: 'DATA4',
   value: 24,
 }, {
   name: 'DATA5',
   value: 22,
 }, {
   name: 'DATA6',
   value: 30,
 }, {
   name: 'DATA7',
   value: 20,
 }, {
   name: 'DATA8',
   value: 41,
 }, {
   name: 'DATA9',
   value: 31,
 }, {
   name: 'DATA10',
   value: 30,
 }, {
   name: 'DATA11',
   value: 30,
 }, {
   name: 'DATA12',
   value: 30,
 }, {
   name: 'DATA13',
   value: 30,
 }, {
   name: 'DATA14',
   value: 30,
 }, ];



 var options = {

   width: 600,
   height: 600,

   margins: {
     top: 100,
     right: 100,
     bottom: 100,
     left: 100
   },

   circles: {
     levels: 6,
     maxValue: 100,
     labelFactor: 1.15,
     opacity: 0.2,
   },

 };


 var allAxis = (data.map(function(i, j) {
     return i.name
   })),
   total = allAxis.length,
   radius = Math.min(options.width / 2, options.height / 2),
   angleSlice = Math.PI * 2 / total,
   Format = d3.format('');

 var rScale = d3.scale.linear()
   .domain([0, options.circles.maxValue])
   .range([50, radius]);

 var svg = d3.select("body").append("svg")
   .attr("width", options.width + options.margins.left + options.margins.right)
   .attr("height", options.height + options.margins.top + options.margins.bottom);

 var g = svg.append("g")
   .attr("transform", "translate(" + (options.width / 2 + options.margins.left) + "," + (options.height / 2 + options.margins.top) + ")");

 var axisGrid = g.append("g")
   .attr("class", "axisWraper");

 var axis = axisGrid.selectAll(".axis")
   .data(allAxis)
   .enter()
   .append("g")
   .attr("class", "axis")

 //append them lines
 axis.append("line")
   .attr("x1", 0)
   .attr("y1", 0)
   .attr("x2", function(d, i) {
     var tempX2 = radius * Math.cos(angleSlice * i - Math.PI / 2);
     return tempX2;
   })
   .attr("y2", function(d, i) {
     var tempY = radius * Math.sin(angleSlice * i - Math.PI / 2);
     return tempY;
   })
   .attr("class", "line")
   .attr("stroke", "black")
   .attr("fill", "none");

 //Draw background circles
 axisGrid.selectAll(".levels")
   .data([6, 5, 4, 3, 2, 1])
   .enter()
   .append("circle")
   .attr("class", "gridCircle")
   .attr("r", function(d, i) {
     return parseInt(radius / options.circles.levels * d, 10);
   })
   .attr("stroke", "black")
   .attr("fill-opacity", options.circles.opacity);

 //Write data
 axis.append("text")
   .attr("class", "labels")
   .attr("font-size", "12px")
   .attr("font-family", "Montserrat")
   .attr("text-anchor", "middle")
   .attr("fill", "black")
   .attr("transform", function(d, i) {
     var rotate = angleSlice * i > Math.PI ? (angleSlice * i * 180 / Math.PI) - 270 : (angleSlice * i * 180 / Math.PI) - 90;
     return "translate(" + radius * Math.cos(angleSlice * i - Math.PI / 2) * options.circles.labelFactor + "," + radius * Math.sin(angleSlice * i - Math.PI / 2) * options.circles.labelFactor + ") rotate(" + rotate + ")"
   })
   .text(function(d) {
     return d;
   });
<script src="https://d3js.org/d3.v3.min.js"></script>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...