web-dev-qa-db-ja.com

D3 .merge関数

D3 APIを何度も読みながら、D3のマージ機能を理解するのに苦労しています。

APIは次のように述べています。「このメソッドは、データ結合後の選択項目の入力と更新をマージするためによく使用されます。

これは、強制ティックチャートでの、おそらくティックの関数がすべてのティックで呼び出される、おそらくそれを簡単に使用する例です。

var simulation = d3.forceSimulation(nodes)
    .force("charge", chargeForce)
    .force("center", centerForce)
    .on("tick", ticked);

    function ticked() {

    var u = d3.select("svg").selectAll("circle").data(nodes)

    u.enter().append("circle").attr("r",5)
        .merge(u) // What is the merge function doing here?
        .attr("cx", d => d.x)
        .attr("cy", d => d.y)

    u.exit().remove() // Why is it necessary to remove excess objects w/ the exit selection?

    }

データバインディングの仕組みと、enter()およびexit()の選択の仕組みを理解しています。ただし、これまで「マージ」を使用する必要はなかったため、ここで行っていることがわかりません。誰かがこの機能で何が起こっているかをステップごとに簡単に説明できれば、非常に便利です。他の人にも同様の質問があると思います。

12
Harry Cramer

ドキュメントはその関数が何をするかを非常によく説明しているので、あなたがこれをする代わりにそれがすることは

_u.attr("cx", d => d.x)
 .attr("cy", d => d.y);

u.enter().append("circle").attr("r",5)
        .attr("cx", d => d.x)
        .attr("cy", d => d.y);
_

attrを一度呼び出すだけです

_u.enter().append("circle").attr("r",5)
        .merge(u) // after this point, any updates will apply to both u and u.enter() selections
        .attr("cx", d => d.x)
        .attr("cy", d => d.y)
_

cx-更新選択とu.enter()- enter選択の両方に属性cyuを設定します

出口選択で余分なオブジェクトを削除する必要があるのはなぜですか?

出口の選択には、data()に渡した配列内の要素にバインドされていない追加のDOM要素が含まれているため、u.exit().style(...)などremoveを呼び出す代わりにDOMから削除します

8
Teedeez

実際には、2つの問題があります。

  1. merge()メソッドの理解;
  2. 共有したコードを理解します。

#1については、すでに回答を受け取っています。 #2に関しては、これらは私の2セントです。そのコードはnotを意味します。

これは簡単に理解できます。ticked関数は1秒間に何十回も実行されます。なぜデータを再バインドして更新を再割り当てし、1秒間に何十回も選択を開始および終了しますデータが変更されない場合? (そのコードの作成者は優れたプログラマーであり、ここで何か奇妙なことが起こっていることに言及する価値があります...結局のところ、私たちは皆間違いを犯します)

ticked関数は、要素の位置を計算する必要があるだけです。

ticked関数でリンクした同じコードは、これに単純化されています。

function ticked() {
    u.attr('cx', function(d) {
            return d.x;
        })
        .attr('cy', function(d) {
            return d.y;
        })
}

そして、ここで実行中のコード:

var width = 600,
  height = 400;

var colorScale = ['orange', 'lightblue', '#B19CD9'];
var xCenter = [100, 300, 500]

var numNodes = 100;
var nodes = d3.range(numNodes).map(function(d, i) {
  return {
    radius: Math.random() * 25,
    category: i % 3
  }
});

var u = d3.select('svg g')
  .selectAll('circle')
  .data(nodes);

var enter = u.enter()
  .append('circle')
  .attr('r', function(d) {
    return d.radius;
  })
  .style('fill', function(d) {
    return colorScale[d.category];
  });

u = enter.merge(u);

u.exit().remove();

var simulation = d3.forceSimulation(nodes)
  .force('charge', d3.forceManyBody().strength(5))
  .force('x', d3.forceX().x(function(d) {
    return xCenter[d.category];
  }))
  .force('collision', d3.forceCollide().radius(function(d) {
    return d.radius;
  }))
  .on('tick', ticked);

function ticked() {
  u.attr('cx', function(d) {
      return d.x;
    })
    .attr('cy', function(d) {
      return d.y;
    })
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="content">
  <svg width="700" height="400">
    <g transform="translate(50, 200)"></g>
  </svg>
</div>
4
Gerardo Furtado

TL; DR-マージにより、2つのノードコレクションが1つになります

var x = d3.selectAll(".node");
var y = d3.selectAll(".link");
var z = x.merge(y);

zには、xのすべての要素とyのすべての要素が含まれるようになりました。

1
user2728841