I'm stuck in d3 (or JavaScript in general).
I want to make a legend with d3. The position of the 9 items should be dependent on each other. More specifically:
This is my simplified array: var dataset = ["Africa","Asia", "Caribbean", "Central America", "Europe", "Middle East", "North America", "Oceania", "South America"];
On the x-axis, I want to draw the next text 40px futher (to the right) then the last text lable ended. My intention is to have the same space between the circles every time. So the next text is always dependent on the length of the last country name.
I tried this:
.attr("x", function(d, i) {return i * 40 + d[i-1].length + 7;})
but the console says d[i-1] is undefined.
What am I missing? How would you solve this?
Many thanks in advance! Your help is very much appreciated!
Ewa
UPDATE: Actually the legend I want to draw not only consists of the text, but also little circles.
Here is the array (with hard coded x_pos as d[2]: var dataset = [ ["Africa", "#4B7985", 5], ["Asia", "#58AB86", 55], ["Caribbean", "#63A4B5", 100], ["Central America", "#818181", 165], ["Europe", "#E9726C", 255], ["Middle East", "#E3AC73", 310], ["North America", "#B65856", 383], ["Oceania", "#287E5C", 470], ["South America", "#AC8358", 530] ];
How do I draw the circles dependent on the length of the country names and get the same spacing between the cirlces?
I'm stuck in d3 (or JavaScript in general).
I want to make a legend with d3. The position of the 9 items should be dependent on each other. More specifically:
This is my simplified array: var dataset = ["Africa","Asia", "Caribbean", "Central America", "Europe", "Middle East", "North America", "Oceania", "South America"];
On the x-axis, I want to draw the next text 40px futher (to the right) then the last text lable ended. My intention is to have the same space between the circles every time. So the next text is always dependent on the length of the last country name.
I tried this:
.attr("x", function(d, i) {return i * 40 + d[i-1].length + 7;})
but the console says d[i-1] is undefined.
What am I missing? How would you solve this?
Many thanks in advance! Your help is very much appreciated!
Ewa
UPDATE: Actually the legend I want to draw not only consists of the text, but also little circles.
Here is the array (with hard coded x_pos as d[2]: var dataset = [ ["Africa", "#4B7985", 5], ["Asia", "#58AB86", 55], ["Caribbean", "#63A4B5", 100], ["Central America", "#818181", 165], ["Europe", "#E9726C", 255], ["Middle East", "#E3AC73", 310], ["North America", "#B65856", 383], ["Oceania", "#287E5C", 470], ["South America", "#AC8358", 530] ];
How do I draw the circles dependent on the length of the country names and get the same spacing between the cirlces?
Share Improve this question edited Dec 4, 2013 at 8:59 Ewa asked Nov 26, 2013 at 18:02 EwaEwa 291 silver badge9 bronze badges3 Answers
Reset to default 6You can draw text element to get bounding box on canvas. Then adjust position based on the last element's width:
svg.selectAll("text")
.data(data).enter()
.append("text")
.attr("x", function(d) {
return x_pos;
})
.attr("y", 50)
.style("display", "none")
.text(function(d) { return d; });
svg.selectAll("text")
.style("display", "block")
.attr("x", function(d) {
var c_pos = x_pos;
x_pos = x_pos + this.getBBox().width + distance;
return c_pos;
});
Full example: https://vida.io/documents/C5CSjbWLhoJ8rQmhF
This is how I would do it.
//This will be your array of legends
var legendItems = []
var legendCount = legendItems.length;
var legendSectionWidth = width / (legendCount+1);
//This will be your "y" value going forward. You can assign anything you want. I have used the following if else case, you should replace it with your logic to calculate y.
var vert = 0;
if(legendPosition == "bottom"){
if(showAxes)
vert = height + legendVerticalPad + containerHeight*0.04;
else
vert = height + legendVerticalPad + containerHeight*0.02;
}
for(var i = 0; i < legendCount; i++){
var text = svg.append('text')
.attr('x', (i+1)*legendSectionWidth)
.attr('y', vert)
.attr('class', 'legend-text '+legendItems[i])
.style('text-anchor', 'middle')
.style('dominant-baseline', 'central')
.text(function() {
return legendItems[i];
});
var len = text[0][0].getComputedTextLength();
// you could use circles here, just change the width n height to rx and x and y to cx and cy// you could use circles here, just change the width n height to rx and x and y to cx and cy`enter code here`
//The value 5 is your choice, i use 5px between my rect and text
svg.append('rect')
.attr('x', (i+1)*legendSectionWidth - len/2 - 5 - legendRectSize)
.attr('y', vert - legendRectSize/2)
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.attr('class', function () { return 'legend '+ legendItems[i];} )
.attr('label', function() {
return legendItems[i];
})
}
The result is something like this
The following images prove that the legends(bo of rect and text) are equi-distant from each and place right in the center of the provided width. And with this logic, no matter what is the no of legends you need, all will be placed equi-distant from each other and show up right in the middle of the screen
I hope this helps.
First off, d
refers to an individual, bound data point, while i
refers to its index in the dataset. To look at the previous data point, you would need to reference the original dataset, rather than the provided datapoint.
Assuming you had:
var dataset = ["Africa","Asia", "Caribbean", "Central America", "Europe", "Middle East", "North America", "Oceania", "South America"];
d3.select('.foo').data(dataset)....
You would want to change your d[i - 1] references in your position handler to dataset[i - 1]
With that fixed, your first element will still blow up, since it's at dataset[0]
. dataset[i - 1]
is dataset[-1]
in that case.
You could change your return statement to:
return i ? (i * 40 + dataset[i-1].length + 7) : i;
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745359010a4624274.html
评论列表(0条)