移动 g 元素使它们在树形布局中居中
Move g element for centering them in a tree layout
我想移动 g 元素包含多个 tspan 文本以输入。
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>
属性 dx 和 dy 在此示例中不起作用。移动 g 元素以使其移动到中心的正确方法是什么?
为了动态地重新定位它们,一个简单的方法是获取元素的大小并将其 up/left 转换为 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})`)
});
这里是你的代码有那个变化:
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>
我想移动 g 元素包含多个 tspan 文本以输入。
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>
属性 dx 和 dy 在此示例中不起作用。移动 g 元素以使其移动到中心的正确方法是什么?
为了动态地重新定位它们,一个简单的方法是获取元素的大小并将其 up/left 转换为 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})`)
});
这里是你的代码有那个变化:
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>