简体   繁体   中英

D3 z-index of links and nodes

I got an D3v4 graph in place, where I can dynamical add nodes. My problem is that each added node draws the link above the selected node. Adjusting the z-index seems nothing to change. The addNode() creates a new link and new node for now. The node is a mix between hard coded and dynamical yet. Further I push the newly created link to the original graph array and the same for the node.

Any hints how I can fix the problem?

黄色标记问题

In following the addNode() I am using:

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

Z-index doesn't work on svg. Svg will draw elements by the order they appear.

So you need to add the nodes after the links, so they are on top.

Because you are adding new nodes/links at a later stage, you can do this:

  1. Create the parent containers (first one for links, then one for nodes)
var linksContainer = svg.append('g').attr('class', 'linksContainer');
var nodesContainer = svg.append('g').attr('class', 'nodesContainer');
  1. Now you can add and update your nodes and links to the containers, instead in the svg, and you ensure that the nodes are always on top of the links

Eg: (I hope I didn't miss any 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()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM