Reputation: 38
I have drawn a few concentric arcs on my SVG following the code below :-
var width = 2000;
var height = 500;
var canvas = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height);
var group = canvas.append("g")
.attr("transform","translate(100,200)");
var arc = d3.svg.arc()
.innerRadius(function(d){return (d-1)})
.outerRadius(function(d){return d})
.startAngle(1)
.endAngle(p/2);
var arcs = group.selectAll(".arc")
.data(orbitRadius)
.enter()
.append("g")
.attr("class","arc");
arcs.append("path")
.attr("d",arc);
Here orbitRadius array holds the radius for each arc.
Now I want to find out "n" points (x and y co-ordinate) on each arc which are at the same height on each of the arcs. The four points on an arc can be equi-distant. That is, say p1,p2,p3,p4 are 4 points or arc 1, and q1,q2,q3,q4 are 4 points on arc 2, then p1 and q1 are at same height (w.r.t the SVG), p2 and q2 are at same height so on and so forth.
Please help.
Edit :- Please find the image of what I am trying to achieve :- at https://www.dropbox.com/s/w87118tphnmya7a/image.PNG
Upvotes: 1
Views: 3247
Reputation: 9128
You're going to need to use some trig to figure out where to place the points, but the logic shouldn't be all that difficult.
You know the radius of each arc, and presumably you know the heights (y-values) that each set of matching points should be at.
Have a look at this unit-circle diagram:
In our case, instead of a unit circle, we have a known radius R which is the radius of the current arc, but the math works the same way.
The missing value that you need to find for each arc is x. To find that, we first need to find what the angle is. Here's where the trig comes in, good old SOH-CAH-TOA.
Given the right triangle as shown in the diagram, we know that:
sin(theta) = y / R
so to find the angle itself, we can just take the inverse sine, or arcsin:
theta = asin(y / R)
We also know that:
cos(theta) = x / R
So putting those together, we get:
cos(asin(y / R)) = x / R
solve for x:
x = cos(asin(y / R)) * R
We can then use this to create a function that, given a y-value and a radius, gives back the x-value:
function getPointX(y, radius) {
return Math.cos(Math.asin(y/radius)) * radius;
}
Now that we have that all out of the way, on to the d3 part.
To plot your points you'll need to make an array of the values you wish to use for your heights, relative to the origin of your arcs. Remember that in SVG coordinates, higher values of y mean lower on your diagram. Therefore, distance below the origin is positive, and distance above it is negative. As an example:
var heights = [-70, -15, 20, 60];
Next I'm going to create a combined dataset.
var combinedData = orbitRadius.map(function(d) {
return {
r: d,
heights: heights
};
});
This creates an array of objects, where each object has a property r
which is one of the radii from orbitRadius
and each object also contains the array of heights
.
There's a bit of unnecessary redundancy in having each object contain the same heights array, but it will make the drawing part simpler to do it this way.
To draw the points, I'll first make a group to contain the points on each separate arc:
var pointGroup = group.selectAll('.point-group')
.data(combinedData)
.enter().append('g')
.attr('class', 'point-group');
Here's the tricky part. I'll then use a nested selection to create a point at each separate height. For the .data()
, we'll use a function of the data from the pointGroup selection, which returns only the array of heights. This means that the enter selection will contain one element for each separate height.
pointGroup.selectAll('.point')
.data(function(d) {return d.heights;})
.enter().append('circle')
.attr('class', 'point')
.attr('cx', function(d) {
return getPointX(d, this.parentNode.__data__.r);
})
.attr('cy', function(d) {return d;})
.attr('r', 4);
The cy
attribute is simply d
since the heights data represents y-values. For the cx
I'm calling the getPointX()
function we made before, passing in the y-value, and the parent node's radius value, since the parent node is the group of all points sharing a radius.
Here's a working example as a JSBin.
Upvotes: 4