使用 d3.join 时是否可以不重新排序元素?

Mar*_*ger 6 javascript visualization data-visualization d3.js typescript

在 中d3,我们可以更改选择中元素的顺序,例如使用raise

然而,当我们重新绑定数据并使用 时join,该顺序将被丢弃。

enter当我们使用绑定数据的“旧方法”(使用和 )时,这种情况不会发生merge

请参阅下面的小提琴,您可以在其中单击一个圆圈(例如蓝色圆圈)将其置于前面。当您单击“重绘”时,使用 时,圆会恢复到原来的 z 顺序join,但使用enter和时则不会merge

我可以实现圆圈保持其 z 顺序并仍然使用吗join

const data = [{
  id: 1,
  v: 10,
  c: 'red'
}, {
  id: 2,
  v: 30,
  c: 'blue'
}, {
  id: 3,
  v: 60,
  c: 'green'
}]

let nDrawCall = 0

function redraw() {
  nDrawCall++
  //svg1 with old enter-merge pattern that works
  const circles = d3.select('#svg1')
    .selectAll('circle')
    .data(data, d => d.id)
  circles
    .enter()
    .append('circle')
    .on('click', function() {
      d3.select(this).raise()
    })
    .merge(circles)
    .attr('cx', d => d.v * nDrawCall)
    .attr('cy', d => d.v)
    .attr('r', d => d.v)
    .attr('fill', d => d.c)
    
  //svg2 with new join pattern that sadly reorders
  d3.select('#svg2')
    .selectAll('circle')
    .data(data, d => d.id)
    .join(enter => enter
      .append('circle')
      .on('click', function() {
        d3.select(this).raise()
      })
    )
    .attr('cx', d => d.v * nDrawCall)
    .attr('cy', d => d.v)
    .attr('r', d => d.v)
    .attr('fill', d => d.c)
}

function reset() {
  nDrawCall = 0
  redraw()
}

redraw()

/*
while (true) {
  iter++
  console.log(iter)
  sleepFor(500)
}
*/
Run Code Online (Sandbox Code Playgroud)
svg {
  height: 100px;
  width: 100%;
}
Run Code Online (Sandbox Code Playgroud)
<html>
  <head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/d3.min.js"></script>
  </head>
  <body>
    <button onclick="redraw()">
      Redraw
    </button>
    <button onclick="reset()">
      Reset
    </button>
    <div>
      <svg id="svg1" />  
      <svg id="svg2" />
    </div>
  </body>

</html>
Run Code Online (Sandbox Code Playgroud)

der*_*hda 3

joinorder合并输入和更新选择后执行隐式操作,请参阅https://github.com/d3/d3-selection/blob/91245ee124ec4dd491e498ecbdc9679d75332b49/src/selection/join.js#L14

即使文档顺序发生更改,示例中数据绑定后的选择顺序仍然是红、蓝、绿。因此,使用 将圆圈重新排序为原始顺序join

您可以通过更改反映文档顺序更改的数据绑定来解决这个问题。我在这里通过将单击的圆圈的数据移动到数据数组的末尾来做到这一点。

let data = [{
  id: 1,
  v: 10,
  c: 'red'
}, {
  id: 2,
  v: 30,
  c: 'blue'
}, {
  id: 3,
  v: 60,
  c: 'green'
}]

let nDrawCall = 0

function redraw() {
  nDrawCall++
  d3.select('#svg2')
    .selectAll('circle')
    .data(data, d => d.id)
    .join(enter => enter
      .append('circle')
      .on('click', function() {
        const circle = d3.select(this).raise();
        data.push(data.splice(data.indexOf(circle.datum()), 1)[0]);
      })
    )
    .attr('cx', d => d.v * nDrawCall)
    .attr('cy', d => d.v)
    .attr('r', d => d.v)
    .attr('fill', d => d.c)
}

function reset() {
  nDrawCall = 0
  redraw()
}

redraw()
Run Code Online (Sandbox Code Playgroud)
svg {
  height: 100px;
  width: 100%;
}
Run Code Online (Sandbox Code Playgroud)
<html>
  <head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/d3.min.js"></script>
  </head>
  <body>
    <button onclick="redraw()">
      Redraw
    </button>
    <button onclick="reset()">
      Reset
    </button>
    <div>
      <svg id="svg2" />
    </div>
  </body>

</html>
Run Code Online (Sandbox Code Playgroud)