Bagaimana cara menghapus semua elemen anak dari sebuah node dan kemudian menerapkannya lagi dengan warna dan ukuran yang berbeda?

87

Jadi saya memiliki kode grafik tata letak gaya berikutnya untuk mengatur node, tautan, dan elemen lainnya:

var setLinks = function ()
{
    link = visualRoot.selectAll("line.link")
        .data(graphData.links)
        .enter().append("svg:line")
        .attr("class", "link")
        .style("stroke-width", function (d) { return nodeStrokeColorDefault; })
        .style("stroke", function (d) { return fill(d); })
        .attr("x1", function (d) { return d.source.x; })
        .attr("y1", function (d) { return d.source.y; })
        .attr("x2", function (d) { return d.target.x; })
        .attr("y2", function (d) { return d.target.y; });

    graphData.links.forEach(function (d)
    {
        linkedByIndex[d.source.index + "," + d.target.index] = 1;
    });
};


var setNodes = function ()
{
    node = visualRoot.selectAll(".node")
        .data(graphData.nodes)
        .enter().append("g")
        .attr("id", function (d) { return d.id; })
        .attr("title", function (d) { return d.name; })
        .attr("class", "node")
        .on("click", function (d, i) { loadAdditionalData(d.userID, this); })
        .call(force.drag)
        .on("mouseover", fadeNode(.1)).on("mouseout", fadeNode(1));
};

//append the visual element to the node
var appendVisualElementsToNodes = function ()
{
    node.append("circle")
        .attr("id", function (d) { return "circleid_" + d.id; })
        .attr("class", "circle")
        .attr("cx", function (d) { return 0; })
        .attr("cy", function (d) { return 0; })
        .attr("r", function (d) { return getNodeSize(d); })
        .style("fill", function (d) { return getNodeColor(d); })
        .style("stroke", function (d) { return nodeStrokeColorDefault; })
        .style("stroke-width", function (d) { return nodeStrokeWidthDefault; });

    //context menu:
    d3.selectAll(".circle").on("contextmenu", function (data, index)
    {
        d3.select('#my_custom_menu')
          .style('position', 'absolute')
          .style('left', d3.event.dx + "px")
          .style('top', d3.event.dy + "px")
          .style('display', 'block');

        d3.event.preventDefault();
    });
    //d3.select("svg").node().oncontextmenu = function(){return false;};

    node.append("image")
        .attr("class", "image")
        .attr("xlink:href", function (d) { return d.profile_image_url; })//"Images/twitterimage_2.png"
        .attr("x", -12)
        .attr("y", -12)
        .attr("width", 24)
        .attr("height", 24);

    node.append("svg:title")
        .text(function (d) { return d.name + "\n" + d.description; });
};

Sekarang, dependensi warna dan ukuran berubah dan saya perlu menggambar ulang lingkaran grafik (+ semua elemen yang ditambahkan) dengan warna dan radius yang berbeda. Mengalami masalah.

Aku bisa melakukan ini:

visualRoot.selectAll(".circle").remove();

tapi saya memiliki semua gambar yang saya lampirkan '.circles'masih di sana.

Bagaimanapun, bantuan apa pun akan dihargai, beri tahu saya jika penjelasannya tidak cukup jelas, saya akan mencoba memperbaikinya.

PS apa perbedaan antara graphData.nodes dan d3.selectAll('.nodes')?

HotFrost
sumber

Jawaban:

132

Jawaban Anda akan berhasil, tetapi untuk anak cucu, metode ini lebih umum.

Hapus semua anak dari HTML:

d3.select("div.parent").html("");

Hapus semua anak dari SVG / HTML:

d3.select("g.parent").selectAll("*").remove();

The .html("")panggilan bekerja dengan SVG saya, tapi mungkin efek samping dari menggunakan innerSVG .

Glenn
sumber
3
Sayangnya .html ("") tidak berfungsi di Safari. Bekerja dengan baik di semua browser lain.
mesin terbang
1
@glyph: lihat stackoverflow.com/a/43661877/1587329 untuk cara resmi melakukan ini
serv-inc
8

Saran pertama saya adalah Anda harus membaca d3.jsAPI tentang pilihan: https://github.com/mbostock/d3/wiki/Selections

Anda harus memahami cara kerja enter()perintah ( API ). Fakta bahwa Anda harus menggunakannya untuk menangani node baru memiliki arti yang akan membantu Anda.

Berikut adalah proses dasar saat Anda menangani selection.data():

  • pertama-tama Anda ingin "melampirkan" beberapa data ke pilihan. Jadi kamu punya:

      var nodes = visualRoot.selectAll(".node")
          .data(graphData.nodes)
    
  • Kemudian Anda dapat memodifikasi semua node setiap kali data diubah (ini akan melakukan apa yang Anda inginkan). Jika misalnya Anda mengubah radius node lama yang ada di dataset baru yang Anda muat

      nodes.attr("r", function(d){return d.radius})
    
  • Kemudian, Anda harus menangani node baru, untuk ini Anda harus memilih node baru, inilah yang selection.enter()dibuat untuk:

      var nodesEnter = nodes.enter()
          .attr("fill", "red")
          .attr("r", function(d){return d.radius})
    
  • Akhirnya Anda pasti ingin menghapus node yang tidak Anda inginkan lagi, untuk melakukan ini, Anda harus memilihnya, untuk itulah selection.exit()dibuat.

      var nodesRemove = nodes.exit().remove()
    

Contoh bagus dari keseluruhan proses juga dapat ditemukan di wiki API: https://github.com/mbostock/d3/wiki/Selections#wiki-exit

Christopher Chiche
sumber
HI Chris, terima kasih atas saran dan poinnya. Faktanya, saya tidak punya data baru .. Datanya masih sama. Semua sama. Saya tidak ingin melakukan seluruh proses gaya lagi. Sejauh yang saya mengerti (perbaiki saya jika saya salah). Yang harus saya lakukan adalah
HotFrost
yang harus saya lakukan adalah menemukan elemen dom dengan kelas '.circle' dan anak-anaknya. Hapus mereka. Temukan elemen svg dengan kelas '.node' dan terapkan kembali proses 'lampirkan' untuk lingkaran svg dan visual lainnya yang dijelaskan dalam fungsi 'applyvisualelements', tetapi kali ini ketika radius akan dihitung, itu akan dihitung secara berbeda.
HotFrost
dengan cara apapun, saya telah mengatasinya dengan sangat mudah, visualRoot.selectAll (". circle"). remove (); visualRoot.selectAll (". image"). remove ();
HotFrost
7

dengan cara ini, saya telah menyelesaikannya dengan sangat mudah,

visualRoot.selectAll(".circle").remove();
visualRoot.selectAll(".image").remove();

dan kemudian saya menambahkan kembali elemen visual yang dirender secara berbeda karena kode untuk menghitung radius dan warna telah mengubah properti. Terima kasih.

HotFrost
sumber
6

Jika Anda ingin menghapus elemen itu sendiri, gunakan saja element.remove(), seperti yang Anda lakukan. Jika Anda hanya ingin menghapus konten elemen, tetapi mempertahankan elemen apa adanya, Anda dapat menggunakan f.ex.

visualRoot.selectAll(".circle").html(null);
visualRoot.selectAll(".image").html(null);

alih-alih .html("")(Saya tidak yakin anak elemen mana yang ingin Anda hapus). Ini mempertahankan elemen itu sendiri, tetapi membersihkan semua konten yang disertakan . Ini cara resmi untuk melakukan ini , jadi harus bekerja lintas browser.

PS: Anda ingin mengubah ukuran lingkaran. Sudahkah kamu mencoba

d3.selectAll(".circle").attr("r", newValue);
serv-inc
sumber
html(null)tidak berfungsi untuk saya di Internet Explorer 11
Robert
@Robert: "Nilai null akan menghapus konten." Sepertinya bug. Ada yang dilaporkan ke konsol?
serv-inc
Tidak, tidak ada kesalahan atau peringatan. Hanya mengembalikan objek yang dipilih. d3.select($0).html('')dari jawaban yang dipilih juga tidak berfungsi untuk saya di IE, tetapi d3.select($0).selectAll('*').remove()berfungsi.
Robert
@ Robert: Apakah Anda ingin melaporkan ini ?
serv-inc
3

Untuk menghapus semua elemen dari sebuah node:

var siblings = element.parentNode.childNodes;
for (var i = 0; i < siblings.length; i++) {
    for (var j = 0; j < siblings.length; j++) {
        siblings[i].parentElement.removeChild(siblings[j]);
    }
}`
jedd.ahyoung
sumber
Anda seam untuk mengutip sesuatu, apa sumbernya?
Christopher Chiche
Apakah Anda benar-benar perlu juga menghapus semua node tersebut dari node mereka sendiri. Tentunya metode yang direkomendasikan DOM akan mencukupi karena node tidak akan keluar dari node saat ini tidak perlu dirobek juga.
Tatarize
var element = document.getElementById ("top"); while (element.firstChild) {element.removeChild (element.firstChild); }
Tatarize