D3.js在svg结构中移动元素



我之所以写信给您,是因为我正在为D3.js(D3选择(在SVG中移动现有元素的位置而苦苦挣扎。

我看到了很多创建新元素的例子,但在这里,我的元素已经创建好了。

我的svg中有这样的结构:

<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>

我的目标是将所有椭圆移动到主组中以获得:

<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>

我已经成功地用D3.js中的一个部分和一个使用DOM操作的部分实现了这一点。

svg = d3.select('svg')
allellipses = svg.selectAll('ellipse').nodes()
for (ell of allellipses) {document.querySelector('.main').append(ell)}

有没有一种方法只使用D3.js?我想用D3.js函数替换document.querySelector。至少,了解和理解附加现有元素的工作原理。

但是,对于这个操作,只使用简单的DOM操作可能更有效。

selection.remove((从DOM中移除节点,返回这些节点的选择。

selection.append((可以提供一个附加给定节点的函数。

因此,我们可以删除节点,将节点用作数据数组,并输入/附加我们删除的省略号:

var ellipse = svg.selectAll("ellipse").remove();
svg.select("#maingroup")
.selectAll(null)
.data(ellipse.nodes())
.enter()
.append(d=>d);

var svg = d3.select("svg");
var ellipse = svg.selectAll("ellipse").remove();
svg.select("#maingroup")
.selectAll(null)
.data(ellipse.nodes())
.enter()
.append(d=>d);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="30" ry="20"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
</svg>

当然,我们跳过数据绑定,使用selection.remove((和selection.each((将删除的元素附加到不同的父元素:

var ellipse = svg.selectAll("ellipse")
.remove()
.each(function() {
svg.select("#maingroup").append(()=>this);
})

var svg = d3.select("svg");
var ellipse = svg.selectAll("ellipse")
.remove()
.each(function() {
svg.select("#maingroup").append(()=>this);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="25" rx="30" ry="20"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
</svg>

使用selection.insert((而不是selection.append((可以在排序附加元素方面提供更大的灵活性。

最后,我们可以使用selection.append((和一个返回节点的函数,并结合for循环:来调整您的代码

var ellipses = svg.selectAll("ellipse").remove();
for(ellipse of ellipses) svg.select("#maingroup").append(()=>ellipse);

var svg = d3.select("svg");
var ellipses = svg.selectAll("ellipse").remove();
for(ellipse of ellipses) svg.select("#maingroup").append(()=>ellipse);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<svg>
<g id='maingroup' class='main'>
<title>titlemain</main>
<text id='text'>textContent</text>
</g>
<g id='othergroup1' class='othergroup'>
<title>othergroup1</title>
<text id='text1'>textContent1</text>
<ellipse fill="#ac08b6" cx="198.5" cy="30" rx="30" ry="20"></ellipse>
</g>
<g id='othergroup2' class='othergroup'>
<title>othergroup2</title>
<text id='text2'>textContent2</text>
<ellipse fill="#23d5f6" cx="198.5" cy="25" rx="27" ry="18"></ellipse>
</g>
</svg>

当然,优先选择主组会比每次迭代都选择它更有效,而且纯javascript应该更具性能。

最新更新