D3v4 вставка новых узлов

1

EDIT: добавлен пример codepen

Я экспериментирую с симуляцией силы D3v4, но в настоящее время я не могу правильно добавить новые узлы в график. Здесь настройка

var svgRef = d3.select("body").append("svg")
    .attr("width",svgWidth)
    .attr("height",svgHeight)
    .on("mousedown",svgClick);

var nodes_data = [{id: "0"},{id: "1"},{id: "2"}];
var links_data = [{source:"1",target:"2"}];

var linksRef = svgRef
    .selectAll(".link")         
    .data(links_data).enter()
    .append("line").attr("class", "link");

var nodesRef = svgRef
    .append("g").attr("class", "nodes")
    .selectAll(".node")
    .data(nodes_data).enter()
    .append("g").attr("class", "node")
    .call(d3.drag()...);

nodesRef.append("circle")
    .attr("r", nodeRadius);

Я создаю группу для отдельных узлов, чтобы держать их circle title и text и т.д., И все эти узлы создаются в большей группе "узлы". Конечный результат выглядит следующим образом:

<svg>
    ...
    <g class="nodes">
        <g class="node">
            <circle>
            <text>
            ...
        </g>
        <g class="node"></g>
        <g class="node"></g>
        ...
    </g>
</svg>

Затем я добавляю новый узел к своим данным и пытаюсь вставить его в график

function svgClick(){

    // add new node
    nodes_data.push({id: nodeCount++, "x":d3.event.X, "y":d3.event.y});

    // restart simulation
    simulation.nodes(nodes_data).on("tick", ticked);

    // insert new nodes
    nodeEnter = svgRef
        .selectAll(".node")
        .data(nodes_data).enter()
        .append("g").attr("class", "node")
        .call(d3.drag()...)
        .append("circle")
            .attr("class", "node")
            .attr("r", nodeRadius);

    // merge new nodes
    nodesRef = nodeEnter.merge(nodesRef);
}

2 вещи, которые идут не так, что я не могу исправить:

  • вставленный узел не отображается в координатах мыши. Вычислите это, просто опечатку в d3.event.X где X должен быть нижним.

  • вставленный узел не добавляется в <g class="nodes"> но ниже. Я не могу найти способ правильно выбрать его

Вот так:

<svg>
    <g class="nodes">
        <g class="node"></g>
        <g class="node"></g>
    </g>
    <g class="node"></g>  // <--- inserted here
</svg>
  • 1
    Я пытался дать вам ответ, но некоторые данные отсутствуют. Не могли бы вы создать Codepen, чтобы помочь людям помочь вам? Вы можете начать отсюда codepen.io/macio/pen/GrQWrK .
  • 0
    Вот и вы! codepen.io/mrelemental/pen/vabBNz
Теги:
d3.js

1 ответ

1
Лучший ответ

Для вашей второй проблемы: "вставленный узел не добавлен, но ниже. Я не могу найти способ его правильно выбрать", как вы вводите новые узлы, объясняет, почему вы в конечном итоге со структурой, которую у вас есть:

nodeEnter = svgRef
 .selectAll(".node")   // select all elements with class node in the svg
 .data(nodes_data)     // bind new data to them
  .enter()             // enter new nodes where needed
 .append("g")          // append a g for each new node needed to the svg

Это добавляет новые узлы прямо к родительскому svg: svgRef.selectAll(...)...

Если мы хотим добавить новые узлы к родительскому, мы должны сначала выбрать этого родителя. Если бы мы хотели использовать g с nodes класса в качестве родительского элемента для новых узлов, мы бы использовали: svgRef.select(".nodes").selectAll(...)...

Это будет выглядеть так:

nodeEnter = svgRef
  .select(".nodes")     // select the parent g with class nodes
  .seleactAll(".node")  // select all nodes in that parent
  .data(nodes_data)     // bind new data to them
  .enter()              // enter new nodes where needed
  .append("g")          // append a g for each new node needed to the g with class nodes

Кроме того, вы хотите, чтобы nodeEnter был g элементами, а не элементами circle, чтобы вы могли разделить цепочку. Кругам также не нужен узел класса, поскольку родительский элемент g имеет его

Для позиционирования вы используете d3.event.X а не d3.event.x а в кодефене, в отличие от вопроса, вы используете свойства cx, cy для узла (сила принимает позицию как x, y свойства).

Здесь обновляется ручка.

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

  • 0
    Я обновил перо с помощью select(".nodes") но получаю странный результат, когда узлы не перерисовываются. Нужно ли мне .restart () где-нибудь?
  • 1
    @VincentDM, мои извинения, я не добавил требуемый оператор selectAll: .select(".nodes").selectAll(".nodes") во второй блок кода ответа - я скопировал первый блок кода и сделал только половину модификация, ручка в ответе должна быть правильной все же все же. Я обновил ответ, чтобы исправить ошибку.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню