简体   繁体   中英

D3JS including previous elements of legend

I have four pie charts representing different data, made using d3JS library. They are made correctly, but when I include their legend, elements from previous chart's legend also get included in the next chart. So in the last chart's legend, all previous chart's legend's elements are present.

The code is this:

/*var divSkills, divKnows, divEnvs, divTools;

var dataSkills = [
  { label: 'Web Designing', count: 86 }, 
  { label: 'Web Development / Web Programming', count: 90 },
  { label: 'Graphic Designing / Logo Designing', count: 65 },
  { label: 'Programming', count: 73 },
  { label: 'Networking', count: 63 },
  { label: 'Content Writing', count: 56 }
];
var dataKnows = [
  { label: 'PHP', count: 75 }, 
  { label: 'SQL', count: 59 },
  { label: 'HTML 5', count: 90 },
  { label: 'CSS 3', count: 93 },
  { label: 'JavaScript', count: 80 },
  { label: 'C', count: 75 }
];
var dataEnvs = [
  { label: 'Adobe Dreamweaver', count: 75 }, 
  { label: 'SublimeText', count: 80 },
  { label: 'Notepad++', count: 80 },
  { label: 'Cloud9 (Online IDE)', count: 80 }
];
var dataTools = [
  { label: 'Adobe Photoshop', count: 65 }, 
  { label: 'Adobe Illustrator', count: 30 },
  { label: 'Adobe Fireworks', count: 50 },
  { label: 'AutoDesk Maya', count: 40 },
  { label: 'Git / GitHub / GitLab (Control Version System)', count: 70 }
];

var dataset = [dataSkills, dataKnows, dataEnvs, dataTools];

var width = 360;
var height = 360;
var radius = Math.min(width, height) / 2;
var color = d3.scale.category20b();

var legendRectSize = 18;
var legendSpacing = 4;

$(document).ready(function () {

    divSkills = d3.select(".view-graph section:first-child .graph"),
    divKnows = d3.select(".view-graph section:nth-child(2) .graph"),
    divEnvs = d3.select(".view-graph section:nth-child(3) .graph"),
    divTools = d3.select(".view-graph section:last-child .graph");
    var divs = [divSkills, divKnows, divEnvs, divTools];

    var arc = d3.svg.arc()
          .outerRadius(radius);
    var pie = d3.layout.pie()
          .value(function(d) { return d.count; })
          .sort(null);*/

    for (var i = 0; i < divs.length; i++) {
        var svg = divs[i]
              .append('svg')
              .attr('width', width)
              .attr('height', height)
              .append('g')
              .attr('transform', 'translate(' + (width / 2) +  ',' + (height / 2) + ')');
        var path = svg.selectAll('path')
              .data(pie( dataset[i]) )
              .enter()
              .append('path')
              .attr('d', arc)
              .attr('fill', function(d, i) { 
                return color(d.data.label);
        });

        var legend = svg.selectAll('.legend')
              .data(color.domain())
              .enter()
              .append('g')
              .attr('class', 'legend')
              .attr('transform', function(d, j) {
                var height = legendRectSize + legendSpacing;
                var offset =  height * color.domain().length / 2;
                var horz = 15 * legendRectSize;
                var vert = j * height - offset;
                return 'translate(' + horz + ',' + vert + ')';
              });
        legend.append('rect')
              .attr('width', legendRectSize)
              .attr('height', legendRectSize)
              .style('fill', color)
              .style('stroke', color);
        legend.append('text')
              .attr('x', legendRectSize + legendSpacing)
              .attr('y', legendRectSize - legendSpacing)
              .text(function(d) { return d; });
    }

});

As you can see, I am using a for loop to avoid repetition. I tried to fix it by making several variations in the code, but none of them worked. Here is a Pen of this. Now, I have two questions:

  1. How to solve this issue ?
  2. (optional) How to make this code more efficient, as I in learning stage?

Most of the code is taken from this tutorial .

Edit: Commented out irrelevant code.

Your problem is data-binding on color.domain() . As you do color(d.data.label) in each iteration, the domain grows. Throw a

console.log(color.domain());

before you build each legend. You'll see:

["Web Designing", "Web Development / Web Programming", "Graphic Designing / Logo Designing", "Programming", "Networking", "Content Writing"]
["Web Designing", "Web Development / Web Programming", "Graphic Designing / Logo Designing", "Programming", "Networking", "Content Writing", "PHP", "SQL", "HTML 5", "CSS 3", "JavaScript", "C"]
["Web Designing", "Web Development / Web Programming", "Graphic Designing / Logo Designing", "Programming", "Networking", "Content Writing", "PHP", "SQL", "HTML 5", "CSS 3", "JavaScript", "C", "Adobe Dreamweaver", "SublimeText", "Notepad++", "Cloud9 (Online IDE)"]
["Web Designing", "Web Development / Web Programming", "Graphic Designing / Logo Designing", "Programming", "Networking", "Content Writing", "PHP", "SQL", "HTML 5", "CSS 3", "JavaScript", "C", "Adobe Dreamweaver", "SublimeText", "Notepad++", "Cloud9 (Online IDE)", "Adobe Photoshop", "Adobe Illustrator", "Adobe Fireworks", "AutoDesk Maya", "Git / GitHub / GitLab (Control Version System)"]

An easy fix would be to data-bind to:

 var pieLabels = dataset[i].map(function(d){
     return d.label;
 });

 var legend = svg.selectAll('.legend')
     .data(pieLabels);

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