svglabellegenddiscrete

Issue with displaying label for the discrete legends after using view box attribute for svg


I have created the discrete legend using svg and I want to show the index as its label.

// creating svg
selectedLegend
.append("svg")
.attr("viewBox", `0 0 ${count} 1`)
.attr("preserveAspectRatio", "none")

function legend(g: any) {
// appending data
g.selectAll("g.legendCells")
.data(itemColor)
.enter()
.append("rect");
// appending text for label, which is not working as expected
g.selectAll("rect")
.append("text")
.attr("class", "breakLabels")
.style("fill", "red")
.attr("x", cellWidth + cellPadding)
.attr("y", 5 + cellHeight / 2)
.text(function (d: Record<string, unknown>, i: any) {
// return the index, which should be label for legend
return i;
});
}

Fiddle link : https://jsfiddle.net/03bxhoyq/2/

I want like below red it must show label as 0 and 1 for blue and so on.

Something like this but please note the image is vertical legend and mine in horizontal.

enter image description here


Solution

  • Be careful not to place the <text> elements as children to <rect>. They are independent. The scaling (preserveAspectRatio="none") also apply to the text, so it could be a good idea to have an SVG inside another SVG. The inner SVG has the scaling and the outer SVG has the texts. The outer SVG has a viewBox that matches the height/width ratio (10 to 1 is = to 250 to 25).

    On the <text> I added the attributes dominant-baseline="middle" and text-anchor="middle" to position the handle of the text in the middle of it.

    <div id="container">
      <svg viewBox="0 0 20 2" width="400px">
        <svg viewBox="0 0 4 1" preserveAspectRatio="none" width="100%" height="1" >
          <rect x="0" y="0" height="1" width="1" style="fill: rgb(255, 46, 0);"/>
          <rect x="1" y="0" height="1" width="1" style="fill: rgb(0, 184, 0);"/>
          <rect x="2" y="0" height="1" width="1" style="fill: rgb(0, 25, 255);"/>
          <rect x="3" y="0" height="1" width="1" style="fill: rgb(179, 179, 179);"/>
        </svg>
        <g dominant-baseline="middle" text-anchor="middle" font-size=".73">
          <text x="2.5" y="1.5" style="fill: black;">0</text>
          <text x="7.5" y="1.5" style="fill: black;">1</text>
          <text x="12.5" y="1.5" style="fill: black;">2</text>
          <text x="17.5" y="1.5" style="fill: black;">3</text>
        </g>
      </svg>
    </div>