简体   繁体   中英

d3js Create legend for bar chart

I'm having a couple of issues with my bar chart. The current issue is trying to create a legend. The legend should read Global and Local (blue & green). Currently the legend generates 5 boxes - 2 of them are colored. I assume it's going through my dataset and generating boxes for each set of columns. I do not want this.

After I get the legend formatted, I want to be able to have it interactive. So if they only want to see global , then they unselect local , and the chart updates dynamically. I know I'll need to adjust it and create a function to update data, domain, etc.

But before beginning down that road, I want to get the legend populating properly. But I would appreciate if the legend solution would lead down this road.

I have a working Fiddle you can play around with .

Data Sources

var colors =    {0: ["Local", "#377EB8"],
             1: ["Global", "#4DAF4A"]};

var dataset = [
            {"keyword": "payday loans", "global": 1400000, "local": 673000, "cpc": "14.11"},
            {"keyword": "title loans", "global": 165000, "local": 160000, "cpc": "12.53" },
            {"keyword": "personal loans", "global": 550000, "local": 301000, "cpc": "6.14"},
            {"keyword": "online personal loans", "global": 15400, "local": 12900, "cpc": "5.84"},
            {"keyword": "online title loans", "global": 111600, "local": 11500, "cpc": "11.74"}
        ];

Label Code

var legend = svg.append("g")
    .attr("class", "legend")
    //.attr("x", w - 65)
    //.attr("y", 50)
    .attr("height", 100)
    .attr("width", 100)
    .attr('transform', 'translate(-20,50)');


legend.selectAll('rect')
    .data(dataset)
    .enter()
    .append("rect")
    .attr("x", w - 65)
    .attr("y", function(d, i) {
        return i * 20;
    })
    .attr("width", 10)
    .attr("height", 10)
    .style("fill", function(d) {
        var color = colors[dataset.indexOf(d)][1];
        return color;
    });

legend.selectAll('text')
    .data(dataset)
    .enter()
    .append("text")
    .attr("x", w - 52)
    .attr("y", function(d, i) {
        return i * 20 + 9;
    })
    .text(function(d) {
        var text = colors[dataset.indexOf(d)][0];
        return text;
    });

I know my Colors array/object probably isn't the most efficient way. So I'm open to adjusting that if it helps with the solution. Also, I would prefer that it is a Horizontal list instead of vertical.

You need to use colors rather than dataset as parameter for the .data() of your legend. In order for that to work, colors has to be an array rather than an object:

var colors = [ ["Local", "#377EB8"],
               ["Global", "#4DAF4A"] ];

The code for creating the legend then becomes:

var legendRect = legend.selectAll('rect').data(colors);

legendRect.enter()
    .append("rect")
    .attr("x", w - 65)
    .attr("width", 10)
    .attr("height", 10);

legendRect
    .attr("y", function(d, i) {
        return i * 20;
    })
    .style("fill", function(d) {
        return d[1];
    });

var legendText = legend.selectAll('text').data(colors);

legendText.enter()
    .append("text")
    .attr("x", w - 52);

legendText
    .attr("y", function(d, i) {
        return i * 20 + 9;
    })
    .text(function(d) {
        return d[0];
    });

Cf the updated fiddle .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM