【问题标题】:Change order in which data is drawn in d3更改在 d3 中绘制数据的顺序
【发布时间】:2019-07-02 17:16:40
【问题描述】:

我有一些需要绘制的数据 (Nodes)。这些节点可以重叠,因此绘制它们的顺序很重要(应该显示在顶部的节点需要最后绘制)。

这些节点的位置以及因此的 z 轴可能会发生变化,这就是为什么我尝试使用包含当前 indexkey 来模拟这种行为em> 节点存储在列表中。

case class Node(id: Int)

def addNodesToSVG = {
   val sortedData: List[Node] = ??? 

   val nodesSelection = d3.select("#nodes").selectAll(".node")
      .data(sortedData.toJSArray, (n: Node) => {
         n.id.toString +
         // the position of those nodes may change over time
         // that's why we need to include the position in the identifier
         sortedData.indexOf(n)
   }

   nodesSelection.enter().append("g").attr("class", "node") // ...

   nodesSelection
       .attr("transform", transform) // ...

   nodesSelection.exit().remove()
}

不幸的是,这似乎没有按预期工作。

理论上,如果我只有两个节点(n1n2),我认为这就是我认为的工作方式,它们保存在 List(n1, n2)

node   key
-----  ---
n1      10 // node 1 at position 0
n2      21 // node 2 at position 1

现在,如果我将列表更改为 List(n2, n1) 并再次调用 addNodesToSVG,这就是我认为会发生的事情:

node   key
-----  ---
n2      20 // node 1 at position 0
n1      12 // node 2 at position 1

由于这些是未知的,我认为它将删除 (nodesSelection.exit().remove()) 旧节点并以正确的顺序绘制“新”节点。然而,这并没有发生。为什么?

编辑经过更多调试后,我发现我的 exit 选择的大小始终为 0。

【问题讨论】:

  • nodesSelection.append("g") // ... 这是什么?闻起来像不当使用
  • 是的,你是对的;将我的代码复制到 SO 时我犯了一个错误。抱歉,我编辑了我的问题。

标签: javascript scala d3.js scala.js


【解决方案1】:

我认为 id 函数应该以一致的方式使用——仅仅因为一个对象改变了它的位置,它的 id 函数的结果不应该改变(我认为这是在第一名)。我采取的方法是使 id 函数完全依赖于节点的 id;向指定渲染顺序的数据对象添加一个字段;合并后根据该新字段对选择进行排序。

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
  </style>
</head>

<body>
  <button onclick="sw()">Switch</button>
  <script>
    var d1 = [{
      id: 'a',
      z: 1,
      fill: 'red', 
      y: 0
    }, {
      id: 'b',
      z: 2,
      fill: 'green', 
      y: 5
    }];
    
    var d2 = [{
      id: 'a',
      z: 2, 
      fill: 'red',
      y: 5
    }, {
      id: 'b',
      z: 1, 
      fill: 'green',
      y: 0
    }]
    
    var current = 0;
    
    var svg = d3.select("body").append("svg")
      .attr("width", 100)
      .attr("height", 100)
    	.attr('viewBox', '0 0 10 20');

    function render(d) {
      var r = svg.selectAll('rect')
      	.data(d, function(d) { return d.id; });
      r.enter()
      	.append('rect')
      	.attr('width', 10)
      	.attr('height', 10)
      	.attr('fill', function(d) { return d.fill; })
      .merge(r)
      	.sort(function(r1, r2) {
        	if (r1.z > r2.z) return 1;
        	if (r1.z < r2.z) return -1;
        	return 0;
      	})
      	.transition()
      	.attr('y', function(d) { return d.y; });
      
      r.exit().remove();
    };
    
    function sw() {
        if (current == 0) {
          current = 1;
          render(d2);
        } else {
          current = 0;
          render(d1);
        }
    }
    
    render(d1);

  </script>
</body>

【讨论】:

  • 虽然在我的数据模型中存储有关如何绘制内容 (z) 的信息似乎有点违反直觉,但这个解决方案对我有用。 :) 谢谢。
  • .sort( (r1, r2) =&gt; r1.z - r2.z)
猜你喜欢
  • 1970-01-01
  • 2018-10-25
  • 1970-01-01
  • 2023-02-22
  • 1970-01-01
  • 2014-04-21
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
相关资源
最近更新 更多