Як видалити всі дочірні елементи з вузла, а потім застосувати їх знову з різним кольором та розміром?


87

Отже, у мене є наступний графічний код силового розташування для встановлення вузлів, посилань та інших елементів:

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; });
};

Тепер кольори та залежності від розміру змінилися, і мені потрібно перемалювати кола графіку (+ всі додані елементи) з різним кольором та радіусом. Маючи проблеми з цим.

Я можу це зробити:

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

але у мене є всі зображення, до яких я прикріпив, '.circles'все ще там.

Будь-яким чином будь-яка допомога буде вдячна, повідомте мене, якщо пояснення недостатньо чітке, я спробую це виправити.

PS в чому різниця між graphData.nodes і d3.selectAll('.nodes')?

Відповіді:


130

Ваша відповідь буде працювати, але для нащадків ці методи є більш загальними.

Видалити всіх дочірніх елементів з HTML:

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

Видалити всіх дочірніх елементів із SVG / HTML:

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

.html("")Виклик працює з моїм SVG, але це може бути побічним ефектом використання innerSVG .


3
На жаль .html ("") не працює в Safari. Прекрасно працює у всіх інших браузерах.
гліф

1
@glyph: см stackoverflow.com/a/43661877/1587329 для офіційного способу зробити це
серв-вкл

8

Моя перша порада - вам слід прочитати d3.jsAPI про вибір: https://github.com/mbostock/d3/wiki/Selections

Ви повинні розуміти, як enter()працює команда ( API ). Той факт, що ви повинні використовувати його для обробки нових вузлів, має значення, яке вам допоможе.

Ось основний процес, коли ви маєте справу з selection.data():

  • спочатку ви хочете "приєднати" до вибору деякі дані. Отже, у вас є:

    var nodes = visualRoot.selectAll(".node")
        .data(graphData.nodes)
    
  • Потім ви можете змінювати всі вузли при кожному зміні даних (це буде робити саме те, що ви хочете). Якщо, наприклад, ви змінюєте радіус старих вузлів, які є в новому наборі даних, який ви завантажили

    nodes.attr("r", function(d){return d.radius})
    
  • Потім вам доведеться обробляти нові вузли, для цього вам потрібно вибрати нові вузли, ось для чого selection.enter()створено:

    var nodesEnter = nodes.enter()
        .attr("fill", "red")
        .attr("r", function(d){return d.radius})
    
  • Нарешті, ви, безсумнівно, хочете видалити вузли, які вам більше не потрібні, для цього потрібно їх вибрати, для цього selection.exit()створено.

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

Хороший приклад цілого процесу також можна знайти на вікі API: https://github.com/mbostock/d3/wiki/Selections#wiki-exit


Вітаю, Кріс, дякую за пропозиції та зауваження. Справа в тому, що я не маю нових даних. Дані все ті ж. Все однаково. Я не хочу робити весь процес сили знову. Наскільки я розумію (виправте мене, якщо помиляюся). Все, що мені потрібно зробити, це
HotFrost

все, що мені потрібно зробити, це знайти елементи dom з класом .circle та їх дітьми. Видаліть їх. Знайдіть елементи svg з класом '.node' та повторно застосуйте процес 'приєднання' до кіл svg та інших візуальних елементів, описаних у функції 'applyvisualelements', але цього разу, коли радіус буде обчислений, він буде обчислений по-іншому.
HotFrost

будь-яким чином, я вирішив це дуже легко, visualRoot.selectAll (". коло"). remove (); visualRoot.selectAll (". image"). remove ();
HotFrost

7

таким чином, я вирішив це дуже легко,

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

а потім я просто додав візуальні елементи, які відображались по-різному, оскільки код для обчислення радіуса та кольору змінив властивості. Дякую.


6

Якщо ви хочете видалити сам елемент, просто використовуйте element.remove(), як і раніше. Якщо ви просто хочете видалити вміст елемента, але зберегти його як є, ви можете використовувати f.ex.

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

замість .html("")(я не був впевнений, дочірні елементи якого ви хочете видалити). Це зберігає сам елемент, але очищає весь включений вміст . Це офіційний спосіб зробити це , тому повинен працювати крос-браузер.

PS: Ви хотіли змінити розміри кола. Ти намагався

d3.selectAll(".circle").attr("r", newValue);

html(null)не працює для мене в Internet Explorer 11
Роберт

@Robert: "Нульове значення очистить вміст." Схоже на помилку. Щось повідомлено на консолі?
serv-inc

Ні, помилок та попереджень немає. Просто повертає виділений об'єкт. d3.select($0).html('')з обраної відповіді мені теж не працює в IE, але d3.select($0).selectAll('*').remove()працює.
Роберт

@ Роберт: Ви хочете повідомити про це ?
serv-inc

3

Щоб видалити весь елемент з вузла:

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]);
    }
}`

Ви хочете щось цитувати, що є джерелом?
Christopher Chiche

Вам дійсно потрібно також видалити всі ці вузли зі своїх власних вузлів. Звичайно, рекомендованого методу DOM було б достатньо, оскільки вузли не будуть відключені від поточного вузла, не потрібно також розривати їх.
Татарізувати

var елемент = document.getElementById ("зверху"); в той час як (element.firstChild) {element.removeChild (element.firstChild); }
Татарізувати
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.