89

D3 ライブラリを使用して、SVG 要素を z オーダーの一番上に移動する効果的な方法は何ですか?

私の特定のシナリオは、マウスが特定の部分の上にあるときに( に を追加するstrokeことによって)強調表示される円グラフです。pathチャートを生成するためのコード ブロックは次のとおりです。

svg.selectAll("path")
    .data(d)
  .enter().append("path")
    .attr("d", arc)
    .attr("class", "arc")
    .attr("fill", function(d) { return color(d.name); })
    .attr("stroke", "#fff")
    .attr("stroke-width", 0)
    .on("mouseover", function(d) {
        d3.select(this)
            .attr("stroke-width", 2)
            .classed("top", true);
            //.style("z-index", 1);
    })
    .on("mouseout", function(d) {
        d3.select(this)
            .attr("stroke-width", 0)
            .classed("top", false);
            //.style("z-index", -1);
    });

いくつかのオプションを試しましたが、今のところうまくいきません。両方を使用style("z-index")して呼び出しclassedても機能しませんでした。

「トップ」クラスは、CSS で次のように定義されています。

.top {
    fill: red;
    z-index: 100;
}

ステートメントは、fillそれが正しくオン/オフされていることを私が知っていることを確認するためにあります. です。

使用はオプションだと聞いたことsortがありますが、「選択された」要素を一番上に表示するためにどのように実装されるかは不明です。

アップデート:

次のコードで特定の状況を修正しました。これは、mouseoverイベントの SVG に新しいアークを追加して、ハイライトを表示します。

svg.selectAll("path")
    .data(d)
  .enter().append("path")
    .attr("d", arc)
    .attr("class", "arc")
    .style("fill", function(d) { return color(d.name); })
    .style("stroke", "#fff")
    .style("stroke-width", 0)
    .on("mouseover", function(d) {
        svg.append("path")
          .attr("d", d3.select(this).attr("d"))
          .attr("id", "arcSelection")
          .style("fill", "none")
          .style("stroke", "#fff")
          .style("stroke-width", 2);
    })
    .on("mouseout", function(d) {
        d3.select("#arcSelection").remove();
    });
4

10 に答える 10

93

他の回答で説明されているように、SVG には z-index の概念がありません。代わりに、ドキュメント内の要素の順序が図面内の順序を決定します。

要素を手動で並べ替える以外に、特定の状況では別の方法があります。

D3 を使用すると、常に他のタイプの要素の上に描画する必要がある特定のタイプの要素がよくあります。

たとえば、グラフをレイアウトする場合、リンクは常にノードの下に配置する必要があります。より一般的には、一部の背景要素は通常、他のすべての下に配置する必要があり、一部のハイライトとオーバーレイは上に配置する必要があります。

このような状況にある場合は、これらの要素グループの親グループ要素を作成するのが最善の方法であることがわかりました。gSVG では、そのために要素を使用できます。たとえば、常にノードの下に配置する必要があるリンクがある場合は、次のようにします。

svg.append("g").attr("id", "links")
svg.append("g").attr("id", "nodes")

#ここで、リンクとノードをペイントするときに、次のように選択します (要素 IDで始まるセレクターを参照します)。

svg.select("#links").selectAll(".link")
// add data, attach elements and so on

svg.select("#nodes").selectAll(".node")
// add data, attach elements and so on

現在、すべてのリンクは常にすべてのノード要素の前に構造的に追加されます。したがって、要素を追加または削除する頻度や順序に関係なく、SVG はすべてのノードの下にすべてのリンクを表示します。もちろん、同じタイプ (つまり、同じコンテナー内) のすべての要素は、追加された順序に従います。

于 2013-06-16T12:14:49.127 に答える
56

開発者が提示した解決策の 1 つは、「D3 の並べ替え演算子を使用して要素を並べ替える」ことです。( https://github.com/mbostock/d3/issues/252を参照)

この観点から、データを比較するか、データのない要素の場合は位置を比較して、要素を並べ替えることができます。

.on("mouseover", function(d) {
    svg.selectAll("path").sort(function (a, b) { // select the parent and sort the path's
      if (a.id != d.id) return -1;               // a is not the hovered element, send "a" to the back
      else return 1;                             // a is the hovered element, bring "a" to the front
  });
})
于 2012-12-10T02:02:14.147 に答える
13

SVG は z-index を行いません。Z オーダーは、コンテナー内の SVG DOM 要素の順序によって決定されます。

私が知る限り (過去に数回これを試しました)、D3 は、単一の要素を前面などに移動するために、単一の要素をデタッチおよび再アタッチする方法を提供していません。

選択範囲に表示される順序に一致するようにノードを再シャッフルする.order()メソッドがあります。あなたの場合、単一の要素を前面に持ってくる必要があります。したがって、技術的には、目的の要素を前にして (または最後に、どれが一番上か思い出せない) 選択を再ソートしてから、それを呼び出すorder()ことができます。

または、このタスクの d3 をスキップして、プレーンな JS (または jQuery) を使用して、その 1 つの DOM 要素を再挿入することもできます。

于 2012-11-28T06:14:00.050 に答える
1

既存の SVG で Z オーダーを微調整する方法を見つけるのに何年もかかりました。ツールチップの動作を伴う d3.brush のコンテキストで本当に必要でした。2 つの機能をうまく連携させるには ( http://wrobstory.github.io/2013/11/D3-brush-and-tooltip.html )、d3.brush を Z オーダーの最初にする必要があります。 (最初にキャンバスに描画され、次に残りの SVG 要素によってカバーされます)、その上に何があるかに関係なく、すべてのマウス イベントをキャプチャします (より高い Z インデックスを使用)。

ほとんどのフォーラムのコメントは、最初に d3.brush をコードに追加し、次に SVG の「描画」コードを追加する必要があると述べています。しかし、私は外部 SVG ファイルをロードしたため、それは不可能でした。ブラシはいつでも簡単に追加でき、後で Z オーダーを次のように変更できます。

d3.select("svg").insert("g", ":first-child");

d3.brush セットアップのコンテキストでは、次のようになります。

brush = d3.svg.brush()
    .x(d3.scale.identity().domain([1, width-1]))
    .y(d3.scale.identity().domain([1, height-1]))
    .clamp([true,true])
    .on("brush", function() {
      var extent = d3.event.target.extent();
      ...
    });
d3.select("svg").insert("g", ":first-child");
  .attr("class", "brush")
  .call(brush);

d3.js insert() 関数 API: https://github.com/mbostock/d3/wiki/Selections#insert

お役に立てれば!

于 2014-10-11T02:31:19.310 に答える