I would like move the g element include multiple tspan text to enter.
demo()
function demo() {
//subtitle("iptable filter")
// 2. 描画用のデータ準備
var width = 800
var height = 400
var data = {name:"AAA\nBBB",children: [
{name: "CCC\nDDD",children:[
{name:"EEE\nFFF"}
]},
{name: "GGG\nHHH",children:[
{name:"III\nJJJ"}
]},
{name: "KKK\nLLL",children: [
{name: "MMM\nNNN"}
]},
{name: "OOO\nPPP",children:[
{name: "QQQ\nRRR"}
]}
]}
var root = d3.hierarchy(data);
var tree = d3.tree()
.size([height, width])
tree(root);
var margin = {left:80,top:20,right:20,bottom:20}
var svg = d3.select('body').append("svg")
.attr('width',width margin.left margin.right)
.attr('height',height margin.top margin.bottom)
var g = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter()
.append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" d.y "," d.x
"C" (d.parent.y 100) "," d.x
" " (d.parent.y 100) "," d.parent.x
" " d.parent.y "," d.parent.x;
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" d.y "," d.x ")"; })
var txtnode = node.append("text")
.attr("text-anchor", 'start')
.attr("dominant-baseline","text-before-edge")//"middle"
.attr("font-size", "200%")
.selectAll('tspan')
.data(d => d.data.name.split('\n'))
.join('tspan')
.attr('class','tspan')
.attr('x',0)
.attr('y',(d,i) => i*25)
.text(d => d)
node.each((d,i,n) =>{
var bbox = d3.select(n[i]).node().getBBox()
var margin = 4
bbox.x -= margin
bbox.y -= margin
bbox.width = 2*margin
bbox.height = 2*margin
d.bbox = bbox
})
node.insert("rect",'text')
.attr('fill','#FEFECE')
.attr('fill','none')
.attr('rx',5.5)
.attr('ry',5.5)
.attr('stroke','#A80036')
.attr('stroke-width',2)
.attr('x',d => d.bbox.x)
.attr('y',d => d.bbox.y)
.attr('width',d => d.bbox.width)
.attr('height',d => d.bbox.height)
node.attr('dx',(d,i,n) => {
var x = d.bbox.width/2
return -x
})
.attr('dy',(d,i,n) => {
var x = d.bbox.width/2
var y = d.bbox.height/2
return -y
})
g.selectAll('.link')
.attr('fill','none')
.attr('stroke','#555')
.attr('stroke-opacity',1)
.attr('stroke-width',4)
}
<script src="https://d3js.org/d3.v6.min.js"></script>
The attribute dx and dy doesn't work in this example. what's the proper way to move the g element to make it move to center?
CodePudding user response:
For repositioning them dynamically, an easy approach is getting the size of the element and translating it up/left by half its height/width:
node.each(function(d) {
const thisSize = this.getBoundingClientRect();
d3.select(this).attr("transform", `translate(${d.y - thisSize.width/2},${d.x - thisSize.height/2})`)
});
Here is your code with that change:
demo()
function demo() {
//subtitle("iptable filter")
// 2. 描画用のデータ準備
var width = 800
var height = 400
var data = {
name: "AAA\nBBB",
children: [{
name: "CCC\nDDD",
children: [{
name: "EEE\nFFF"
}]
},
{
name: "GGG\nHHH",
children: [{
name: "III\nJJJ"
}]
},
{
name: "KKK\nLLL",
children: [{
name: "MMM\nNNN"
}]
},
{
name: "OOO\nPPP",
children: [{
name: "QQQ\nRRR"
}]
}
]
}
var root = d3.hierarchy(data);
var tree = d3.tree()
.size([height, width])
tree(root);
var margin = {
left: 80,
top: 20,
right: 20,
bottom: 20
}
var svg = d3.select('body').append("svg")
.attr('width', width margin.left margin.right)
.attr('height', height margin.top margin.bottom)
var g = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter()
.append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" d.y "," d.x
"C" (d.parent.y 100) "," d.x
" " (d.parent.y 100) "," d.parent.x
" " d.parent.y "," d.parent.x;
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter()
.append("g")
.attr("class", "node");
var txtnode = node.append("text")
.attr("text-anchor", 'start')
.attr("dominant-baseline", "text-before-edge") //"middle"
.attr("font-size", "200%")
.selectAll('tspan')
.data(d => d.data.name.split('\n'))
.join('tspan')
.attr('class', 'tspan')
.attr('x', 0)
.attr('y', (d, i) => i * 25)
.text(d => d)
node.each((d, i, n) => {
var bbox = d3.select(n[i]).node().getBBox()
var margin = 4
bbox.x -= margin
bbox.y -= margin
bbox.width = 2 * margin
bbox.height = 2 * margin
d.bbox = bbox
})
node.insert("rect", 'text')
.attr('fill', '#FEFECE')
.attr('fill', 'none')
.attr('rx', 5.5)
.attr('ry', 5.5)
.attr('stroke', '#A80036')
.attr('stroke-width', 2)
.attr('x', d => d.bbox.x)
.attr('y', d => d.bbox.y)
.attr('width', d => d.bbox.width)
.attr('height', d => d.bbox.height)
node.attr('dx', (d, i, n) => {
var x = d.bbox.width / 2
return -x
})
.attr('dy', (d, i, n) => {
var x = d.bbox.width / 2
var y = d.bbox.height / 2
return -y
})
g.selectAll('.link')
.attr('fill', 'none')
.attr('stroke', '#555')
.attr('stroke-opacity', 1)
.attr('stroke-width', 4)
node.each(function(d) {
const thisSize = this.getBoundingClientRect();
d3.select(this).attr("transform", `translate(${d.y - thisSize.width/2},${d.x - thisSize.height/2})`)
});
}
<script src="https://d3js.org/d3.v6.min.js"></script>