在D3.js中如何创建一个包含2行的水平图例?
这是创建图例的当前JavaScript代码:
var legendGroup = svg.append("g")
.attr("transform", "translate("+(width-50)+",30)");
var legend = legendGroup.selectAll(".legend")
.data(nations.map(d=>d.name))
.enter()
.append("g")
.attr("transform", (d,i)=>"translate(0," + 20*i + ")")
var legendRects = legend.append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("fill", d=> colorScale(d));
var legendText = legend.append("text")
.attr("x", 14)
.attr("y", 8)
.text(d=>d);
答案 0 :(得分:4)
您发布的代码是一列,如您所述,因为它将图例的每个部分翻译为最后一个:"translate(0," + 20*i + ")"
以下20个像素。通过操作translate语句,如果知道数组中有多少个元素,就可以创建一个2行图例,但即使不知道,也可以指定每行中有多少个元素。
在以下代码块中,n
指的是一行中应有多少项,itemWidth
表示每个图例条目宽度的像素值,itemHeight
表示高度。
我不知道你有多少个传奇项目,但你可以这样设置:
.attr("transform", function(d,i) { return
"translate(" + i%n * itemWidth +
"," +
Math.floor(i/n) * itemHeight + ")"; })
这应该是这样的:
var data = ["Cat A","Cat B","Cat C", "Cat D", "Dog A", "Dog B", "Dog C", "Dog D"];
var n = data.length/2;
var itemWidth =80;
var itemHeight = 18;
var svg = d3.select("svg");
var color = d3.scale.category10();
var legend = svg.selectAll(".legend")
.data(data)
.enter()
.append("g")
.attr("transform", function(d,i) { return "translate(" + i%n * itemWidth + "," + Math.floor(i/n) * itemHeight + ")"; })
.attr("class","legend");
var rects = legend.append('rect')
.attr("width",15)
.attr("height",15)
.attr("fill", function(d,i) { return color(i); });
var text = legend.append('text')
.attr("x", 15)
.attr("y",12)
.text(function(d) { return d; });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500" height="100"></svg>
编辑: 这是一个移动整个水平图例的片段(根据下面的评论,使用四行在这个狭窄的视图中更好地向右侧显示移动):
var data = ["Cat A","Cat B","Cat C", "Cat D", "Dog A", "Dog B", "Dog C", "Dog D"];
var n = data.length/4;
var itemWidth =80;
var itemHeight = 18;
var width = 500;
var svg = d3.select("svg");
var color = d3.scale.category10();
var legendGroup = svg.append("g")
.attr("transform", "translate("+(width-150)+",10)");
var legend = legendGroup.selectAll(".legend")
.data(data)
.enter()
.append("g")
.attr("transform", function(d,i) { return "translate(" + i%n * itemWidth + "," + Math.floor(i/n) * itemHeight + ")"; })
.attr("class","legend");
var rects = legend.append('rect')
.attr("width",15)
.attr("height",15)
.attr("fill", function(d,i) { return color(i); });
var text = legend.append('text')
.attr("x", 15)
.attr("y",12)
.text(function(d) { return d; });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500" height="200"> </svg>
答案 1 :(得分:0)
const legendData = ['The United States', 'Brazil', 'India', 'China', 'United Arab Emirates'] // The names which you want to appear as legends should be inside this array.
const legend = d3.select('svg')
.append('g')
.attr('transform', 'translate(' + (margin.left + margin.right + 60) + ',' + (margin.top - 20) + ')')
.selectAll('g')
.data(legendData)
.enter()
.append('g');
legend.append('rect')
.attr('fill', (d, i) => color(d)) // const color = d3.scaleOrdinal(d3.schemeCategory10);
.attr('height', 15)
.attr('width', 15);
legend.append('text')
.attr('x', 18)
.attr('y', 10)
.attr('dy', '.15em')
.text((d, i) => d)
.style('text-anchor', 'start')
.style('font-size', 12);
// Now space the groups out after they have been appended:
const padding = 10;
legend.attr('transform', function (d, i) {
return 'translate(' + (d3.sum(legendData, function (e, j) {
if (j < i) { return legend.nodes()[j].getBBox().width; } else { return 0; }
}) + padding * i) + ',0)';
});