Bhavesh Jadav
Bhavesh Jadav

Reputation: 705

Center SVG group element

I am trying to center g element having text with tspan inside svg element using d3 using below code.

var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()

var x = rootSVGSize.width / 2;
var y = rootSVGSize.height / 2;

d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
   <g class="data-label">
      <text alignment-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
         <tspan x="0" dy="0">1/1/2018</tspan>
         <tspan x="0" dy="41">3:00:00</tspan>
         <tspan x="0" dy="41">AM</tspan>
      </text>
      <title>1/1/2018 3:00:00 AM</title>
   </g>
</svg>

As you can see after executing above code, the group element is not centered correctly on x and y coordinates. How can I make group element center inside svg?

I am using getBoundingClientRect becuase I want to get size of svg at initial stage after assigning width and height that is before anything is rendred inside svg.

Upvotes: 2

Views: 6137

Answers (2)

Gerardo Furtado
Gerardo Furtado

Reputation: 102184

You have to take into account the x and y position of both the SVG container and the group:

var x = (rootSVGSize.x - dataLabelSize.x) + (rootSVGSize.width - dataLabelSize.width) / 2;
var y = (rootSVGSize.y - dataLabelSize.y) + (rootSVGSize.height - dataLabelSize.height) / 2;

That way, you can have any value you want for alignment-baseline, dominant-baseline and text-anchor, it doesn't matter, the group will be always centered.

Here is your code with that change:

var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()

var x = (rootSVGSize.x - dataLabelSize.x) + (rootSVGSize.width - dataLabelSize.width) / 2;
var y = (rootSVGSize.y - dataLabelSize.y) + (rootSVGSize.height - dataLabelSize.height) / 2;

d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
   <g class="data-label">
      <text alignment-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
         <tspan x="0" dy="0">1/1/2018</tspan>
         <tspan x="0" dy="41">3:00:00</tspan>
         <tspan x="0" dy="41">AM</tspan>
      </text>
      <title>1/1/2018 3:00:00 AM</title>
   </g>
</svg>

Upvotes: 4

enxaneta
enxaneta

Reputation: 33044

I've made a few changes in the svg, the most important: I've changed some values for the tspan's dy. Also I'm using dominant-baseline="middle" instead of alignment-baseline="middle". I hope it helps.

var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()

var x = rootSVGSize.width / 2;
var y = rootSVGSize.height / 2;

d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
   <g class="data-label">
      <text dominant-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
         <tspan x="0" dy="-41">1/1/2018</tspan>
         <tspan x="0" dy="41">3:00:00</tspan>
         <tspan x="0" dy="41">AM</tspan>
      </text>
      <title>1/1/2018 3:00:00 AM</title>
   </g>
</svg>

Upvotes: 0

Related Questions