f.bele
f.bele

Reputation: 367

Placing elements on circle line and rotating them towards the center using D3.js

I have found many similar questions to what I need, but none of the answers quite told me how to achieve what I need. I want to have 27 ticks as elements to be placed around the three third of the circle and all of them to be pointed (rotated) to the center. Basically, what I want to achieve is this:

click here

I have also written following code:

html,
body,
#wrapper {
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="wrapper">
</div>
<script>
  var svg = d3.select('#wrapper')
    .append('svg')
    .attr({
      'width': '100%',
      'height': '100%',
      'fill': '#adadad'
    });

  var data = d3.range(27).map(function(i) {
    return {
      'x': i,
      'y': i
    };
  });

  var xcos = d3.scale.linear()
    .domain([0, data.length])
    .range([Math.PI * 0.8, Math.PI * 2.2]);

  var xcos1 = d3.scale.linear()
    .domain([0, data.length])
    .range([0, Math.PI]);

  var ysin = d3.scale.linear()
    .domain([0, data.length])
    .range([Math.PI * 0.8, Math.PI * 2.2]);
  var innerRadius = 148;
  var outerRadius = 150;

  var arc = d3.svg.arc()
    .innerRadius(innerRadius)
    .outerRadius(outerRadius)
    .startAngle(-2)
    .endAngle(2);

  var grp = svg.append('g')
    .attr('transform', 'translate(200,200)');

  var line = grp.selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
    .attr('width', 4)
    .attr('height', 22)
    .attr('transform', function(d, i) {
      var rx = Math.cos(xcos(i)) * outerRadius;
      var ry = Math.sin(ysin(i)) * outerRadius + (Math.cos(xcos(i)) * 11);
      return 'translate(' + rx + ', ' + ry + ')';
    })
</script>

If there is any better solution to this, any recommendation is much appreciated. I would also like to achieve to have the dash which is placed above the last filled out rectangle, as it is seen in the picture.

Upvotes: 2

Views: 322

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

You have to rotate the rectangles as well:

return 'translate(' + rx + ', ' + ry + ')rotate(' + (xcos(i) * 180/Math.PI + 90)  + ')';

Here is your code with that change (and without the bit that turned the circle asymmetrical):

html,
body,
#wrapper {
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="wrapper">
</div>
<script>
  var svg = d3.select('#wrapper')
    .append('svg')
    .attr({
      'width': '100%',
      'height': '100%',
      'fill': '#adadad'
    });

  var data = d3.range(27).map(function(i) {
    return {
      'x': i,
      'y': i
    };
  });

  var xcos = d3.scale.linear()
    .domain([0, data.length])
    .range([Math.PI * 0.85, Math.PI * 2.2]);

  var xcos1 = d3.scale.linear()
    .domain([0, data.length])
    .range([0, Math.PI]);

  var ysin = d3.scale.linear()
    .domain([0, data.length])
    .range([Math.PI * 0.85, Math.PI * 2.2]);
  var innerRadius = 148;
  var outerRadius = 150;

  var grp = svg.append('g')
    .attr('transform', 'translate(200,200)');

  var line = grp.selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
    .attr('width', 4)
    .attr('height', 22)
    .attr('transform', function(d, i) {
      var rx = Math.cos(xcos(i)) * outerRadius;
      var ry = Math.sin(ysin(i)) * outerRadius;
      return 'translate(' + rx + ', ' + ry + ')rotate('+ (xcos(i) * 180/Math.PI + 90)  +')';
    })
</script>

Upvotes: 2

Related Questions