Как мне удалить все дочерние элементы из узла, а затем применить их снова с другим цветом и размером?

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')?

HotFrost
источник

Ответы:

129

Ваш ответ будет работать, но для потомков эти методы более общие.

Удалите всех дочерних элементов из 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
serv-inc
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' и повторно примените процесс 'attach' для кругов svg и других визуальных элементов, описанных в функции 'applyvisualelements', но на этот раз, когда будет рассчитан радиус, он будет рассчитываться по-другому.
HotFrost
в любом случае, я решил это очень легко, visualRoot.selectAll (". circle"). remove (); visualRoot.selectAll (". изображение"). remove ();
HotFrost
7

таким образом, я решил это очень легко,

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

а затем я просто повторно добавил визуальные элементы, которые отображались по-другому, потому что код для расчета радиуса и цвета изменил свойства. Спасибо.

HotFrost
источник
6

Если вы хотите удалить сам элемент, просто используйте element.remove(), как вы это сделали. Если вы просто хотите удалить содержимое элемента, но оставить его как есть, вы можете использовать f.ex.

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

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

PS: вы хотели изменить размеры круга. Попытался ли ты

d3.selectAll(".circle").attr("r", newValue);
serv-inc
источник
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]);
    }
}`
jedd.ahyoung
источник
Вы пытаетесь что-то процитировать, каков источник?
Кристофер Чиче
Вам действительно нужно удалить все эти узлы из их собственных узлов. Конечно, рекомендованного метода DOM будет достаточно, поскольку узлы не будут отключены от текущего узла, и его тоже не нужно разрывать.
Tatarize
var element = document.getElementById ("верх"); while (element.firstChild) {element.removeChild (element.firstChild); }
Tatarize