Reputation: 705
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
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
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