score:1

Accepted answer

problem

your problem has to do with this code

legend
.append("text")
.attr("x", width + 85)
.attr("y", function (d, i) {
  return i * 20 + 9;
})
// .attr("dy", "0.32em")
.text(
  words.map(function (d, i) {
    return d.key; // list of words
  })
);

you are appending only a single text element and in the text function you are returning the complete array of words, which is why all words are shown.

solution

create a corresponding text element for each legend rectangle and provide the correct word. there are multiple ways to go about it.

you could use foreignobject to append html inside your svg, which is very helpful for text, but for single words, plain svg might be enough.

i advise to use a g element for each legend item. this makes positioning a lot easier, as you only need to position the rectangle and text relative to the group, not to the whole chart.

here is my example:

let legendgroups = legend
.selectall("g.legend-item")
.data(words)
.enter()
.append("g")
.attr("class", "legend-item")
.attr("transform", function(d, i) {
  return `translate(${width + 65}px, ${i * 20}px)`;
});

legendgroups
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 10)
.attr("height", 10)
.style("fill", function (d) {
  return color(d.key);
});


legendgroups 
.append("text")
.attr("x", 20)
.attr("y", 9)
.text(function(d, i) { return words[i].key; });

this should work as expected. please note the use of groups for easier positioning.


Related Query

More Query from same tag