【问题标题】:D3.js Moving elements in the svg structureD3.js 在 svg 结构中移动元素
【发布时间】:2021-09-19 14:57:06
【问题描述】:

我给你写信是因为我正在努力使用 D3.js(D3-selection)来移动 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 操作会更有效。

【问题讨论】:

    标签: javascript svg dom d3.js


    【解决方案1】:

    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 应该更具性能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-25
      • 2017-10-01
      • 1970-01-01
      • 2015-02-17
      • 2014-07-25
      • 1970-01-01
      • 2019-08-25
      • 2018-02-27
      相关资源
      最近更新 更多