Below sample generate text block but current test is align left, how to align text by center?
demo()
function demo() {
var svg = d3.select('body').append('svg')
.attr('width','100')
.attr('height','100')
.attr('transform','translate(50,50)')
var text = ["12","123456789","1234"]
var fontsize = 40
var txt = svg.append('text')
.attr("text-anchor", 'start')
.attr("dominant-baseline","middle")//text-before-edge
.attr("font-size",fontsize)
.attr('alignment-baseline','middle')
var tspan = txt.selectAll('tspan')
.data(text)
.join('tspan')
.attr('class','tspan')
.attr("x", 0)
.attr('y',function(d,i) {
return i*fontsize
})
.text(d => d)
}
<script src="https://d3js.org/d3.v7.min.js"></script>
Update
After apply @herrstrietzel's answer, I create below demo to show the usecase to put text box at specific position, currently it always at the center of svg, I wish it deployed at specific location (x,y).
demo()
function demo() {
var svg = d3.select('body').append('svg')
.attr('width', 300)
.attr('height', 200)
.style('background','#ececec')
add_grid(svg)
var data = [
{
text:["B", "BB", "BBB",'BBBB'],
x:50,
y:50
},
{
text:["AAAAA", "AAA", "A"],
x:150,
y:100
}
]
var fontsize = 20
var txt = svg.selectAll('.box')
.data(data)
.join('text')
.attr("text-anchor", 'middle')
.attr("x", '50%')
.attr("y", '0%')
.attr("dominant-baseline", "central")
.attr("font-size", fontsize)
.style('border','1px solid red')
.attr('x',d => d.x)
.attr('y',d => d.y)
var tspan = txt.selectAll('tspan')
.data(d => d.text)
.join('tspan')
.attr('class', 'tspan')
.attr("x", '50%')
.attr('dy', function(d) {
return fontsize * 1.2
})
.text(d => d)
function add_grid(svg) {
var w = svg.attr('width')
var step = 10
var mygrid = function(d) {
return `M 0,${d} l ${w},0 M ${d},0 l 0,${w}`
}
var grid = []
for(var i = 0; i < w; i =step) {
grid.push(i);
}
svg.append('g')
.selectAll(null)
.data(grid).enter()
.append('path')
.attr('d',d => mygrid(d))
.attr('fill','none')
.attr('stroke','green')
.attr('stroke-width',.5)
}
}
<script src="https://d3js.org/d3.v7.min.js"></script>
CodePudding user response:
Your text is aligned left since your text-anchor
value is "start" instead of "middle".
Working example
demo()
function demo() {
var svg = d3.select('body').append('svg')
.attr('width', '100')
.attr('height', '100')
//.attr('viewBox','0 0 100 100')
var text = ["12", "123456789", "1234"]
var fontsize = 20
var txt = svg.append('text')
.attr("text-anchor", 'middle')
.attr("x", '50%')
.attr("y", '0%')
.attr("dominant-baseline", "central")
.attr("font-size", fontsize)
var tspan = txt.selectAll('tspan')
.data(text)
.join('tspan')
.attr('class', 'tspan')
.attr("x", '50%')
.attr('dy', function(d) {
return fontsize * 1.2
})
.text(d => d)
}
svg {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script>
dy
can actually be better suited to mimic line breaks.
Worth mentioning:
- there are no block-like elements in svg:
- the parent svg won't automatically grow or shrink according to it's content/child node dimensions ( so you need to calculate an appropriate height and with depending on your text length)
<text>
elements need ax
value of "50%" or "viewBox width/2" to be centered
I strongly recommend to test the best <text>
properties "statically" (e.g. in a codepen or a static html)
Second example:
You need to set the same x
value for both <text>
and <tspan>
elements to mimic a center aligned text block.
Red circles illustrate the desired horizontal/vertical center points.
demo();
function demo() {
var svg = d3
.select("body")
.append("svg")
.attr("width", 300)
.attr("height", 200)
.style("background", "#ececec");
add_grid(svg);
var data = [
{
text: ["B", "BB", "BBB", "BBBB"],
x: 50,
y: 50
},
{
text: ["AAAAA", "AAA", "A"],
x: 150,
y: 100
}
];
var fontsize = 20;
var txt = svg
.selectAll(".box")
.data(data)
.join("text")
.attr("text-anchor", "middle")
.attr("dominant-baseline", "text-bottom")
.attr("font-size", fontsize)
.attr("x", (d) => d.x)
.attr("y", (d) =>{
let textL = d.text.length;
let yOffset = d.y - (fontsize * 1.2 * textL/2);
return (yOffset);
});
var tspan = txt
.selectAll("tspan")
.data((d) => d.text)
.join("tspan")
.attr("class", "tspan")
.attr("x", function (d) {
let currentX = d3.select(this.parentNode).attr("x");
return currentX;
})
.attr("dy", function (d) {
return fontsize * 1.2;
})
.text((d) => d);
function add_grid(svg) {
var w = svg.attr("width");
var step = 10;
var mygrid = function (d) {
return `M 0,${d} l ${w},0 M ${d},0 l 0,${w}`;
};
var grid = [];
for (var i = 0; i < w; i = step) {
grid.push(i);
}
svg
.append("g")
.selectAll(null)
.data(grid)
.enter()
.append("path")
.attr("d", (d) => mygrid(d))
.attr("fill", "none")
.attr("stroke", "green")
.attr("stroke-width", 0.5);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script>
<svg width="300" height="200" style="background: rgb(236, 236, 236);">
<g>
<path fill="none" stroke="green" stroke-width="0.5" d="M0 0l300 0m-300 0l0 300m0-290l300 0m-290-10l0 300m-10-280l300 0m-280-20l0 300m-20-270l300 0m-270-30l0 300m-30-260l300 0m-260-40l0 300m-40-250l300 0m-250-50l0 300m-50-240l300 0m-240-60l0 300m-60-230l300 0m-230-70l0 300m-70-220l300 0m-220-80l0 300m-80-210l300 0m-210-90l0 300m-90-200l300 0m-200-100l0 300m-100-190l300 0m-190-110l0 300m-110-180l300 0m-180-120l0 300m-120-170l300 0m-170-130l0 300m-130-160l300 0m-160-140l0 300m-140-150l300 0m-150-150l0 300m-150-140l300 0m-140-160l0 300m-160-130l300 0m-130-170l0 300m-170-120l300 0m-120-180l0 300m-180-110l300 0m-110-190l0 300m-190-100l300 0m-100-200l0 300m-200-90l300 0m-90-210l0 300m-210-80l300 0m-80-220l0 300m-220-70l300 0m-70-230l0 300m-230-60l300 0m-60-240l0 300m-240-50l300 0m-50-250l0 300m-250-40l300 0m-40-260l0 300m-260-30l300 0m-30-270l0 300m-270-20l300 0m-20-280l0 300m-280-10l300 0m-10-290l0 300" />
</g>
<circle cx="50" cy="50" r="2%" fill="red"/>
<text text-anchor="middle" dominant-baseline="text-bottom" font-size="20" x="50" y="2" style="border: 1px solid red;">
<tspan x="50" dy="24">B</tspan>
<tspan x="50" dy="24">BB</tspan>
<tspan x="50" dy="24">BBB</tspan>
<tspan x="50" dy="24">BBBB</tspan>
</text>
<circle cx="150" cy="100" r="2%" fill="red"/>
<text text-anchor="middle" dominant-baseline="text-bottom" font-size="20" x="150" y="64" style="border: 1px solid red;">
<tspan x="150" dy="24">AAAAA</tspan>
<tspan x="150" dy="24">AAA</tspan>
<tspan x="150" dy="24">A</tspan>
</text>
</svg>