简体   繁体   中英

Vertical alignment between an SVG rect and SVG text using D3 and javascript

In order to practice skills, I am creating my own legend in a D3 graph. I cannot vertically align the svg coloured rect with the correspondent text.

Here my code and a screenshot

mk=[0,1,2,3,4]
var legend_dim=50
var legend_X=300
var colors=["#1f78b4","#33a02c","#e31a1c","#ff7f00","#6a3d9a","#b15928"]

d3.select("#chart").selectAll("rect")
                      .data(mk)
                      .enter()
                      .append("rect")
                      .style("fill", function(d,i) { return colors[i]})                         .attr("x", function(d,i) { return 10*i})
                      .attr("x", legend_X)  
                      .attr("y", function (d,i){return i*legend_dim})
                      .attr("width", legend_dim)
                      .attr("height", legend_dim)



d3.select("#chart").selectAll("text")
                      .data(mk)
                      .enter()
                      .append("text")
                      .text(function(d,i) { return i})
                      .attr("x", legend_X+20)  
                      .attr("y", function (d,i){return (i)*legend_dim})
                      .attr("font-size","12px")

Given that the y property for the 2 is the same, why do the get misaligned? How can I align them? By the way, is there not a way to set the height and width of text box?

在此处输入图片说明

The basic nature of your problem is that:

  • For an svg rectangle, the y value marks the top of the rectangle. Height describes how far below this value the rectangle extends.

  • For text, the y value indicates the y value of the base of each svg character. The characters rise above this line, whereas the rectangles extend below. See the following image, the line is at y=100 and the y value of the svg text is at 100. The text's baseline will be aligned at y=100. However, text with descenders extends lower than this line:

在此处输入图片说明

The challenge in arriving at a clean and definitive resolution to this that font sizes aren't measured from the bottom of the lowest descender to the top of the highest ascender - or even from the font baseline to the top of the highest ascender - but rather to a bounding box that has an arbitrary margin. This topic could be expanded considerably, the moral in this paragraph is that the amount you need to offset text in my proposed solution will vary depending on font and font-size. If you want to take a look down that rabbit hole, this is a good starting point.

Proposed solution:

If you have a rectangle with a known y value, you can add a set value to this to place the text. The offset must be proportional to the text size, and given that font size doesn't correspond to letter height, the value should generally be less than the font size (in pixels). While this could be eyeballed or arbitrarily guessed, a methodical approach could look like:

var fontSize = 50;
svg.append("text")
  .attr("y",rectangleY + fontSize*0.8)
  .attr("x",50)
  .text("|text |")
  .attr("font-size",fontSize);

Alternatively, you could use the dy attribute to set the offset. Set both text and rectangle with the same y , but specify a dy attribute for the text. Both are shown below:

 var svg = d3.select("body") .append("svg") .attr("width",500) .attr("height",200); var yValue = 100; svg.append("rect") .attr("y",yValue) .attr("x",0) .attr("height",50) .attr("width",50) .attr("fill","orange"); // font below: var fontSize = 50; svg.append("text") .attr("y",yValue + fontSize*0.8) .attr("x",50) .text("|text |") .attr("font-size",fontSize); // font below: var fontSize = 50; svg.append("text") .attr("y",yValue) .attr("dy",fontSize*0.8) .attr("x",310) .text("|text |") .attr("font-size",fontSize); // font above: svg.append("text") .attr("y",yValue) .attr("x",180) .text("|text|") .attr("font-size",fontSize); svg.append("line") .attr("x1",0) .attr("x2",400) .attr("y1",100) .attr("y2",100) .attr("stroke","black");
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

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