5
votes

How can I center text both horizontally and vertically on a D3.js SVG grid rect ?

Here is the example I am trying to get working:

https://jsfiddle.net/djangofan/koc74p9x/4/

var columnText = row.selectAll(".column")  // select .column val from data
    .data(function(d) { return d; })
    .enter().append("text")
    .text(function(d) { return d.chord; })
    .attr("x", function(d) { return d.x; })
    .attr("y", function(d) { return d.y; })
    .style("fill", "red");

And here is what it looks like. I want the 'Gm' text to be centered in the first cell. If I try to adjust down, the text disappears as it passes the top border of the cell.

enter image description here

enter image description here

1

1 Answers

2
votes

Move the x and y position by half the width/height:

.attr("x", function(d) {
    return d.x + d.width / 2;
})
.attr("y", function(d) {
    return d.y + d.height / 2;
})

And set both text-anchor and dominant-baseline to middle:

.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")

Finally, move the texts to the top of the rectangles (that is, append them later).

Here is your code with those changes:

function gridConfig() {
  var data = new Array();
  var xpos = 1; //starting xpos and ypos at 1 so the stroke will show when we make the grid below
  var ypos = 80;
  var width = 80;
  var height = 80;
  var click = 0;

  for (var row = 0; row < 8; row++) {
    data.push(new Array());
    for (var column = 0; column < 8; column++) {
      data[row].push({
        rowNum: row + 1,
        columnNum: column + 1,
        x: xpos,
        y: ypos,
        width: width,
        height: height,
        chord: randomChord()
      })
      // increment the x position. I.e. move it over by width variable
      xpos += width;
    }
    // reset the x position after a row is complete
    xpos = 1;
    // increment the y position for the next row. Move it down height variable
    ypos += height;
  }
  return data;
}

function randomChord() {
  var textArray = ['Cm', 'D7', 'Gm', 'Cdim', 'Am', 'Em'];
  return textArray[Math.floor(Math.random() * textArray.length)];
}

var gridData = gridConfig();

var grid = d3.select("#grid")
  .append("svg")
  .attr("width", "810px")
  .attr("height", "890px");

var row = grid.selectAll(".row") // select .row val from data
  .data(gridData)
  .enter().append("g")
  .attr("class", "row")
  .append("g")
  .attr("class", "column");

var column = row.selectAll(".square")
  .data(function(d) {
    return d;
  })
  .enter()
  .append("rect")
  .attr("class", "square")
  .attr("x", function(d) {
    return d.x;
  })
  .attr("y", function(d) {
    return d.y;
  })
  .attr("width", function(d) {
    return d.width;
  })
  .attr("height", function(d) {
    return d.height;
  })
  .style("fill", "#fff")
  .style("stroke", "#222");

var columnText = row.selectAll(".column") // select .column val from data
  .data(function(d) {
    return d;
  })
  .enter()
  .append("text")
  .text(function(d) {
    return d.chord;
  })
  .attr("rowNum", function(d) {
    return d.rowNum;
  })
  .attr("columnNum", function(d) {
    return d.columnNum;
  })
  .attr("x", function(d) {
    return d.x + d.width / 2;
  })
  .attr("y", function(d) {
    return d.y + d.height / 2;
  })
  .attr("text-anchor", "middle")
  .attr("dominant-baseline", "middle")
  .style("fill", "red")
  .style("font-weight", "bold")
  .style("font-size", "24");
<html>
<head>
    <script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="grid"></div>
<script src="grid.js" type="text/javascript"></script>
</body>
</html>