Skip to content Skip to sidebar Skip to footer

How To Create A Horizontal Legend?

In D3.js how can I create a horizontal legend with 2 rows? This is current JavaScript code that creates a legend: var legendGroup = svg.append('g') .attr('transform', 'translat

Solution 1:

The code you posted is a column, as you stated, because it translates each piece of the legend 20 pixels below the last: "translate(0," + 20*i + ")". By manipulating the translate statement you can create a 2 row legend if you know how many elements are in your array, though even if you don't, you can specify how many elements can be in each row.

In the following code block, n refers to how many items should be in a row, itemWidth a pixel value for the width of each legend entry, and itemHeight the height.

I don't know how many legend items you have, but you could set it up as such:

.attr("transform", function(d,i) { return"translate(" + i%n * itemWidth + 
               "," +
               Math.floor(i/n) * itemHeight + ")"; })

This should work like so:

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) { returncolor(i); });
	
var text = legend.append('text')
	.attr("x", 15)
	.attr("y",12)
	.text(function(d) { return d; });
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script><svgwidth="500"height="100"></svg>

Edit: Here's a snippet moving the entire horizontal legend (using four rows to show the movement better to the right side better in this narrow view) based on the comment below:

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) { returncolor(i); });
	
var text = legend.append('text')
	.attr("x", 15)
	.attr("y",12)
	.text(function(d) { return d; });
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script><svgwidth="500"height="200"></svg>

Solution 2:

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 { return0; }
  }) + padding * i) + ',0)';
});

Post a Comment for "How To Create A Horizontal Legend?"