D3 z-индекс ссылок и узлов

У меня есть график D3v4, где я могу динамически добавлять узлы. Моя проблема в том, что каждый добавленный узел рисует ссылку над выбранным узлом. Кажется, что настройка z-index ничего не изменит. addNode() пока создает новую ссылку и новый узел. Узел представляет собой смесь жестко закодированного и динамичного. Далее я нажимаю вновь созданную ссылку на исходный массив графов и то же самое для узла.

Есть подсказки, как я могу решить проблему?

yellow marks the problem

Следуя addNode(), я использую:

function addNode(d) {
    var newid = graph.nodes.length

    var newLink = { source: newid, target: d.id, type: "uses" }
    graph.links.push(newLink)

    graph.nodes.push({
        "id": newid,
        "type": "software",
        "name": "Node",
        "icon": "ue084",
        "parent": d.id,
        "level": d.level + 1,
        "childs": false,
        "context": [
            {
                "name": d.name
            }
        ],
    })

    link = svg.selectAll(".link")
        .data(graph.links)
        .enter()
        .append("line")
        .attr("class", "link")
        .style("pointer-events", "none")
        .attr('marker-end', 'url(#arrowhead)')
        .style("display", "block")
        .merge(link)

    linkPaths = svg.selectAll(".linkPath")
        .data(graph.links)
        .enter()
        .append('path')
        .style("pointer-events", "none")
        .attrs({
            'class': 'linkPath',
            'fill-opacity': 1,
            'stroke-opacity': 1,
            'id': function (d, i) { return 'linkPath' + i }
        })
        .merge(linkPaths)

    linkLabels = svg.selectAll(".linkLabel")
        .data(graph.links)
        .enter()
        .append('text')
        .style("pointer-events", "none")
        .attrs({
            'class': 'linkLabel',
            'id': function (d, i) { return 'linkLabel' + i },
            'font-size': 12,
            'fill': 'black'
        })
        .merge(linkLabels)

    linkLabels.append('textPath')
        .attr('xlink:href', function (d, i) { return '#linkPath' + i })
        .style("text-anchor", "middle")
        .style("pointer-events", "none")
        .attr("startOffset", "50%")
        .text(function (d) { return d.type })
        .merge(linkLabels)

    node = svg.selectAll(".node")
        .data(graph.nodes)
        .enter()
        .append("g")
        .attr("class", "node")
        .attr("stroke", "white")
        .attr("stroke-width", "2px")
        .call(d3.drag()
            .on("start", dragStarted)
            .on("drag", dragged)
            .on("end", dragEnded)
        )
        .on("contextmenu", d3.contextMenu(menu))
        .merge(node)

    node.append("circle")
        .attr("r", 30)
        .style("fill", initialNodeColor)
        .on("mouseenter", mouseEnter)
        .on("mouseleave", mouseLeave)
        .on("click", click)
        .on("dblclick", dblclick)
        .on("contextmenu", d3.contextMenu(menu))
        .merge(node)

    node.append("text")
        .style("class", "icon")
        .attr("font-family", "FontAwesome")
        .attr("dominant-baseline", "central")
        .attr("text-anchor", "middle")
        .attr("font-size", 30)
        .attr("fill", "black")
        .attr("stroke-width", "0px")
        .attr("pointer-events", "none")
        .text(function (d) { return d.icon })
        .on("contextmenu", d3.contextMenu(menu))
        .merge(node)

    simulation.nodes(graph.nodes);
    simulation.force("link").links(graph.links);

    //reheat the simulation
    simulation.alpha(0.3).restart()
}

Всего 1 ответ


Z-index не работает с svg. Svg будет рисовать элементы в порядке их появления.

Итак, вам нужно добавить узлы после ссылок, чтобы они были сверху.

Поскольку вы добавляете новые узлы / ссылки на более позднем этапе, вы можете сделать это:

  1. Создайте родительские контейнеры (сначала один для ссылок, затем один для узлов)
var linksContainer = svg.append('g').attr('class', 'linksContainer');
var nodesContainer = svg.append('g').attr('class', 'nodesContainer');
  1. Теперь вы можете добавлять и обновлять свои узлы и ссылки на контейнеры, а не в svg, и вы гарантируете, что узлы всегда находятся поверх ссылок.

Пример: (надеюсь, я не пропустил ни одного svg)

function addNode(d) {
    var newid = graph.nodes.length

    var newLink = { source: newid, target: d.id, type: "uses" }
    graph.links.push(newLink)

    graph.nodes.push({
        "id": newid,
        "type": "software",
        "name": "Node",
        "icon": "ue084",
        "parent": d.id,
        "level": d.level + 1,
        "childs": false,
        "context": [
            {
                "name": d.name
            }
        ],
    })

    link = linksContainer.selectAll(".link")
        .data(graph.links)
        .enter()
        .append("line")
        .attr("class", "link")
        .style("pointer-events", "none")
        .attr('marker-end', 'url(#arrowhead)')
        .style("display", "block")
        .merge(link)

    linkPaths = linksContainer.selectAll(".linkPath")
        .data(graph.links)
        .enter()
        .append('path')
        .style("pointer-events", "none")
        .attrs({
            'class': 'linkPath',
            'fill-opacity': 1,
            'stroke-opacity': 1,
            'id': function (d, i) { return 'linkPath' + i }
        })
        .merge(linkPaths)

    linkLabels = linksContainer.selectAll(".linkLabel")
        .data(graph.links)
        .enter()
        .append('text')
        .style("pointer-events", "none")
        .attrs({
            'class': 'linkLabel',
            'id': function (d, i) { return 'linkLabel' + i },
            'font-size': 12,
            'fill': 'black'
        })
        .merge(linkLabels)

    linkLabels.append('textPath')
        .attr('xlink:href', function (d, i) { return '#linkPath' + i })
        .style("text-anchor", "middle")
        .style("pointer-events", "none")
        .attr("startOffset", "50%")
        .text(function (d) { return d.type })
        .merge(linkLabels)

    node = nodesContainer.selectAll(".node")
        .data(graph.nodes)
        .enter()
        .append("g")
        .attr("class", "node")
        .attr("stroke", "white")
        .attr("stroke-width", "2px")
        .call(d3.drag()
            .on("start", dragStarted)
            .on("drag", dragged)
            .on("end", dragEnded)
        )
        .on("contextmenu", d3.contextMenu(menu))
        .merge(node)

    node.append("circle")
        .attr("r", 30)
        .style("fill", initialNodeColor)
        .on("mouseenter", mouseEnter)
        .on("mouseleave", mouseLeave)
        .on("click", click)
        .on("dblclick", dblclick)
        .on("contextmenu", d3.contextMenu(menu))
        .merge(node)

    node.append("text")
        .style("class", "icon")
        .attr("font-family", "FontAwesome")
        .attr("dominant-baseline", "central")
        .attr("text-anchor", "middle")
        .attr("font-size", 30)
        .attr("fill", "black")
        .attr("stroke-width", "0px")
        .attr("pointer-events", "none")
        .text(function (d) { return d.icon })
        .on("contextmenu", d3.contextMenu(menu))
        .merge(node)

    simulation.nodes(graph.nodes);
    simulation.force("link").links(graph.links);

    //reheat the simulation
    simulation.alpha(0.3).restart()
}

Есть идеи?

10000