0

I want to make a legend with d3. Position of next element should be depend on previous element.

For ex i have an array like this:

var data =["Saudi - Arabia","Russia","Asia","United - States","Australia"];

This is my javascript code:

                var com_x=0;
                var com_y=0;
                    var legend = d3.select("#chart").append("svg")
                    .attr("class", "legend")
                    .attr("width", r*3)
                    .attr("height", r *1.5)
                    .selectAll("g")
                    .data(data)
                    .enter().append("g")

                   .attr( "transform", function(d,i) { 

                        var currentElementLength = data[i].length;
                        var nextElementLength = 0;

                        if( i < data.length-1)
                            {
                            //alert(i)
                                nextElementLength = data[i+1].length;
                            }
                        //alert(currentElementLength+"  "+nextElementLength+"   "+data[i+1]);
                        if((currentElementLength+nextElementLength) > 16)
                        {
                            x1 = com_x
                            y1 = com_y
                            com_y = com_y+20
                            //alert("One "+i+" "+x1+" "+y1);

                            return "translate(" + x1 + "," + y1 + ")" 
                        }
                        else
                        {
                            x1 = com_x
                            y1 = com_y
                            com_x = com_x+80
                            //alert("Two "+i+" "+x1+" "+y1);
                            return "translate(" + x1 + "," + y1 + ")"
                        }



                } );


legend.append("rect")
                    /* .attr("x",20)
                    .attr("y",-50) */
                    .attr("width", 13)
                    .attr("height", 13)
                    .attr("transform", "translate(10,10)")
                    .style("fill", function(d, i) { return color(i); });

                legend.append("text")
                    /* .attr("x", 42)
                    .attr("y", -41) */
                    .attr("dx", -7)
                    .attr("dy", ".20em")
                    .style("font-size", "14px")
                    .attr("transform", "translate(33,20)")
                    .text(function(d,i) { return data[i]; });

I made as if, current element + next element is greater than 16, next element should be displayed in next row. For first two rows i got the position properly. But for third and fourth row, x position goes wrong. Please check the below link.

Here's my chart!

Is their any way to do dynamically instead of hard-coding?

Any help!!

Developer
  • 157
  • 2
  • 18

1 Answers1

0

At the point you detect the width of the elements is too wide and you increment com_y to position on the next line, you are not resetting com_x back to 0. This is why the 3rd row and later is in the wrong position.

    if((currentElementLength+nextElementLength) > 16)
    {
        x1 = com_x
        y1 = com_y
        com_y = com_y+20
        com_x = 0 // <<---- add this line
        return "translate(" + x1 + "," + y1 + ")" 
    }

On a more general point, you may find that using the length of the text in characters results in some unexpected result if you are using a non-fixed width font; some characters are wider than others. If that becomes an issue, you may need to calculate the pixel-width of the text instead. There are a number of questions that cover that particular topic. For example: SVG get text element width

Community
  • 1
  • 1
knolleary
  • 9,777
  • 2
  • 28
  • 35