Is it possible to specify rangePoints to handle circles of different sizes so that the distances are calculated by their edges rather than their centers?
For example, this is what I am getting:
() represent circle edges; <----> represents distance calculated by rangePoints
( <----)---(-><-)-------(-> )
^Notice how it looks like the middle circle is closer to the left-most circle. Instead, I'd like to see the following:
( )<---->( )<---->( )
The function I am using looks something like:
var y = d3.scale.ordinal()
.domain(data.map(function(d) { return d.value}))
.rangePoints([0, width]);
var item = chart.append("g")
.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cy", function(d) { return y(d.value); })
As @LarsKotthoff mentioned, you're going to need a custom scale implementation to do this.
This is going to be somewhat complex in this case, because the scale needs to take into account not only the number of elements in the domain, but also what their exact values are. Basically, when calculating the position of each element, your scale will need to take into account the space taken up by each element preceding it, and also include a spacer based on a division of the total space.
Here's what it would have to do:
First, in setting up the scale you need to do the following:
This will give you a value for the space needed between each circle.
Then for each element:
Because of this, your scale will need to be based on the index as well as the datum.
Here is a pretty crude implementation that assumes the domain is an array of radii and the range is the endpoints of your output:
var customPointScale = function() {
var domain,
range;
// returned scale fn takes datum and index
function scale(d,i) {
var n = domain.length,
totalSpan = range[1] - range[0],
// loop over the domain to find the sum of the diameters
sumDiameters = (function(){
var output = 0;
for (var a = 0; a < n; a++) {
// add radius * 2 to get diameter
output += domain[a] * 2;
}
return output;
})(),
remainingSpace = totalSpan - sumDiameters,
// there is one fewer space than the number of elements
spacer = remainingSpace / (n-1);
// loop over the elements that came before to find the distance spanned
var distanceSoFar = (function() {
var output = 0;
for(var a = 0; a < i; a++) {
// diameter + spacer, for each element traversed
output += (domain[a] * 2) + spacer;
}
return output;
})();
// return the radius plus the distance traversed so far
return d + distanceSoFar;
}
scale.domain = function(_) {
if (!arguments.length) return domain;
domain = _;
return scale;
};
scale.range = function(_) {
if (!arguments.length) return range;
range = _;
return scale;
};
return scale;
};
Here's a JSBin that uses this implementation with some example data. Hope that helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.