Reputation: 331
I wanna show legend horizontally on top of the chart, I did something like this:
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 30 +
")";
});
legend.append("rect")
.attr("x", function(d, i) {
return (i * 150) + 400;
})
.attr("y", function(d, i) {
return 350;
})
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
My data looks like Rect1 - North, Rect-2 - North East
, my problem here is just alignment of the legend boxes on top of the scatter plot chart.
Upvotes: 1
Views: 2073
Reputation: 102174
The biggest problem of drawing a legend horizontally is the text: since North West
is bigger than East
, you cannot simply hardcode the values to translate.
In this solution, I'll use getComputedTextLength
to (as the name implies) get the length of each text and store those values using D3 locals.
So, when I paint the texts, I store their lengths in the parent <g>
element:
var local = d3.local();
legend.append("text")
.text(String)
.attr("y", function() {
local.set(this.parentNode, this.getComputedTextLength())
return 20;
});
After that, I use that value both to paint the rectangles...
legend.append("rect")
.attr("x", function() {
return local.get(this.parentNode) + 4
});
... and to translate the groups:
legend.each(function(d, i) {
if (i) {
d3.select(this).attr("transform", "translate(" +
(counter += local.get(this.previousSibling) + 36) + ",0)")
}
})
Here is a demo, using this data:
["North", "North East", "North West", "West", "East"];
var svg = d3.select("svg");
var data = ["North", "North East", "North West", "West", "East"];
var colors = d3.scaleOrdinal(d3.schemeCategory10);
var local = d3.local();
var legend = svg.selectAll(null)
.data(data)
.enter()
.append("g");
legend.append("text")
.text(String)
.attr("y", function() {
local.set(this.parentNode, this.getComputedTextLength())
return 20;
});
legend.append("rect")
.style("fill", function(d, i) {
return colors(i)
})
.attr("x", function() {
return local.get(this.parentNode) + 4
})
.attr("y", 6)
.attr("width", 18)
.attr("height", 18);
var counter = 0;
legend.each(function(d, i) {
if (i) {
d3.select(this).attr("transform", "translate(" + (counter += local.get(this.previousSibling) + 36) + ",0)")
}
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="100"></svg>
Upvotes: 2