如何创建水平图例?

时间:2017-02-02 18:24:41

标签: javascript d3.js

在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);

2 个答案:

答案 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)';
});