节点下方的D3 js链接 [英] D3 js links below nodes

查看:75
本文介绍了节点下方的D3 js链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了图形对象,用于创建图形的对象以后可以扩展到更多的节点和链接。
首次创建看起来不错:





然后,使用 add 函数添加节点4并链接:




,如上所示,节点4和3之间的链接绘制在节点3的图像/圆上方。我该如何避免呢?
我的源代码是此处。 / p>

我将附加大部分内容:

 函数Graph(elementId ){
var svg;
var模拟;
var mNodesData = [];
var mEdgesData = [];
var mNode = null;
var mLink = null;
var elementId;
var heightDelta = 100;
var width = window.innerWidth;
var height = window.innerHeight-heightDelta;

return {
init:function(){
svg = d3.select('#'+ elementId)
.append( svg)
.attr( width,width)
.attr( height,height);

模拟= d3.forceSimulation()
.force(。edge,d3.forceLink())
.force( charge,d3.forceManyBody()。 strength(-600))
.force( center,d3.forceCenter(width / 2,height / 2));

mLink = svg.selectAll(。edge)
.attr( class, edge)
.style( stroke, #ccc)
.style( stroke-width,function(e){
return 1
/ * e.width * /
});

mNode = svg.selectAll(。node)
.attr( class, node);
},
clearGraph:function(){
$(’#’+ this.elementId).empty();
},
getNodes:function(){
return mNodesData;
},
getEdges:function(){
return mEdgesData;
},
addNodes:函数(节点){
mNodesData = mNodesData.concat(nodes ;;
},
addEdges:函数(边){
mEdgesData = mEdgesData.concat(edges ;;
},
绘制:function(){
mLink = svg.selectAll(。edge)
.data(mEdgesData)
.enter()
.append( line)
.attr( class, edge)
.style( stroke, #ccc)
.style( stroke- width,函数(e){
返回1
/ * e.width * /
})。merge(mLink);

mNode = svg.selectAll(。node)
.data(mNodesData)
.enter()
.append( g)
.attr( class, node)。merge(mNode);

mNode.call(d3.drag()
.on(开始,拖动开始)
.on(拖动,拖动)
.on( end,被拖拽));

mNode.on('mouseover',function(d){
function removePopup(){
$(#nodePopup)。remove();
}

函数showPopup(d){
removePopup();
if(!d ['data']){
return;
}

var data = d ['data'];
var htmlStr ='';
htmlStr + ='< div id = nodePopup>';
htmlStr + ='< div>< button id = nodePopupCloseButton type = button class = close data-dismiss = alert>< span class = glyphicon glyphicon-remove style = font-size:13px;>< / span>< / div>';;
htmlStr + ='< div class = nodePopupName>'+ data ['name'] +'< ; / div>';
if(data ['desc']){
if(data ['desc']。startsWith( http)){
htmlStr + ='< a class = nodePopupLink href ='+ data ['desc'] +'目标= _ blank>去发布。.< / a>';
}
else {
htmlStr + =’< div class = nodePopupDesc>’+ data [’desc’] +’< / div>’;
}
}
htmlStr + =’< div class = nodePopupGroup> GROUP:‘+ data [’groupId’] +’< / div>’;
htmlStr + =’< div class = nodePopupLeader>领导者:’+ data [’leaderId’] +’< / div>’;
htmlStr + =’< div class = nodePopupImage>< img src =’+ d [’image’] +’ style = width:130px; />< / div>’;
htmlStr + =’< / div>’;

$( body)。append(htmlStr);
$(#nodePopupCloseButton)。click(removePopup);
}

showPopup(d);

mNode.filter(函数(d1){
return(d!== d1&& d1.adjacents.indexOf(d.id)== -1);
})。select( image)。style( opacity,0.2);
mNode.filter(函数(d1){
return(d!== d1&& d1.adjacents.indexOf(d.id)== -1);
}) .select( circle)。style( stroke,#f6f6f6);
mLink.filter(function(d1){
return(d!== d1.source&& d!== d1.target);
})。style( opacity ,0.2);

mNode.filter(function(d1){
return(d == d1 || d1.adjacents.indexOf(d.id)!== -1);
})。select( image)。style( opacity,1);
mNode.filter(function(d1){
return(d == d1 || d1.adjacents.indexOf(d.id)!== -1);
})。select ( circle)。style( stroke, gray);
mLink.filter(function(d1){
return(d == d1.source || d == d1.target);
})。style( opacity,1) ;
})
.on('mouseout',function(){
// removePopup();
mNode.select( image)。style( opacity, 1);
mNode.select( circle)。style( stroke, gray);
mLink.style( opacity,1);
});

var nodeCircle = mNode.append( circle)
.attr( r,函数(d){
返回0.5 * Math.max(d.width, d.height)
})
.attr( stroke, gray)
.attr( stroke-width, 2px)
.attr(填充,白色);

var nodeImage = mNode.append( image)
.attr( xlink:href,函数(d){
返回d.image
} )
.attr( height,函数(d){
return d.height +
})
.attr( width,函数(d){
return d.width +
})
.attr( x,function(d){
return -0.5 * d.width
})
.attr( y,函数(d){
return -0.5 * d.height
})
.attr( clip-path,函数(d) {
return circle( +(0.48 * Math.max(d.width,d.height))+ px)
});


simulation.nodes(mNodesData);
Simulation.force(。edge)。links(mEdgesData);

Simulation.on( tick,function(){
mLink.attr( x1,function(d){
return d.source.x;
})
.attr( y1,函数(d){
return d.source.y;
})
.attr( x2,函数( d){
return d.target.x;
})
.attr( y2,function(d){
return d.target.y;
})

mNode.attr( transform,function(d){
return translate( + dx +, + dy +)
} );
mNode.attr( cx,函数(d){
return dx = Math.max(d.width,Math.min(width-d.width,dx));
})
.attr ( cy,函数(d){
return d.y = Math.max(d.height,Math.min(height-heightDelta-d.height,d.y)));
});
});

函数dragstarted(d){
if(!d3.event.active)Simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}

函数dragged(d){
d.fx = d3.event.x;
d.fy = d3.event.y;
}

函数dragended(d){
if(!d3.event.active)Simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
}
}
}

函数getData(){
return $ .ajax({
url:' api / v1 / data.json',
类型: GET,
});
}

var graph = Graph(’d3Graph’);
graph.init();

$ .when(getData())。then(function(data){
graph.addNodes(data.nodes);
graph.addEdges(data.edges);
graph.draw();

});


函数add(){
graph.addNodes([{
id:4,
image: images / 4。 jpg,
高度:20,
宽度:20,
相邻:[0],
数据:{
名称: Number4,
groupId: Bla4,
desc: Desc4,
leaderId: 1234-1234
}
}]);
graph.addEdges([{{
source:4,
target:3,
width:1
}])
graph.draw();
}


解决方案

由于svg元素位于按照绘制顺序,最后绘制的元素将是最上面的元素。在力的原始绘制之后添加链接时,链接将与节点重叠。有两种解决方案:


  1. 使用.lower()

附加链接时,使用 selection.lower()将其移至底部(这会将选定的元素移至DOM中,以便它们位于其他元素):

  svg.append( line)
.attr(...)
.lower();




  1. 使用多个 g 元素

使用一个 g 链接,先将此添加到SVG。对节点使用第二个 g 。现在,无需将链接和节点附加到同一选择(即svg选择),只需将它们附加到各自的 g 选择中即可。现在, g 元素的添加顺序决定了节点和链接的分层,而与它们添加到可视化文件的顺序无关。


I've created graph object the creates graphs with can later on be extended with more nodes and links. First creation looks good:

Then, with add function I've added node 4 and link:

as you can see above, the link of between node 4 and 3 is drawn above node 3 image/circle. How can I avoid that? my source is code is here.

I'll attach most of it:

        function Graph(elementId) {
        var svg;
        var simulation;
        var mNodesData = [];
        var mEdgesData = [];
        var mNode = null;
        var mLink = null;
        var elementId;
        var heightDelta = 100;
        var width = window.innerWidth;
        var height = window.innerHeight - heightDelta;

        return {
            init: function () {
                svg = d3.select('#' + elementId)
                    .append("svg")
                    .attr("width", width)
                    .attr("height", height);

                simulation = d3.forceSimulation()
                    .force(".edge", d3.forceLink())
                    .force("charge", d3.forceManyBody().strength(-600))
                    .force("center", d3.forceCenter(width / 2, height / 2));

                mLink = svg.selectAll(".edge")
                    .attr("class", "edge")
                    .style("stroke", "#ccc")
                    .style("stroke-width", function (e) {
                        return 1
                        /* e.width*/
                    });

                mNode = svg.selectAll(".node")
                    .attr("class", "node");
            },
            clearGraph: function () {
                $('#' + this.elementId).empty();
            },
            getNodes: function () {
                return mNodesData;
            },
            getEdges: function () {
                return mEdgesData;
            },
            addNodes: function (nodes) {
                mNodesData = mNodesData.concat(nodes);
            },
            addEdges: function (edges) {
                mEdgesData = mEdgesData.concat(edges);
            },
            draw: function () {
                mLink = svg.selectAll(".edge")
                    .data(mEdgesData)
                    .enter()
                    .append("line")
                    .attr("class", "edge")
                    .style("stroke", "#ccc")
                    .style("stroke-width", function (e) {
                        return 1
                        /* e.width*/
                    }).merge(mLink);

                mNode = svg.selectAll(".node")
                    .data(mNodesData)
                    .enter()
                    .append("g")
                    .attr("class", "node").merge(mNode);

                mNode.call(d3.drag()
                    .on("start", dragstarted)
                        .on("drag", dragged)
                        .on("end", dragended));

                mNode.on('mouseover', function (d) {
                    function removePopup() {
                        $("#nodePopup").remove();
                    }

                    function showPopup(d) {
                        removePopup();
                        if (!d['data']) {
                            return;
                        }

                        var data = d['data'];
                        var htmlStr = '';
                        htmlStr += '<div id="nodePopup" >';
                        htmlStr += '    <div><button id="nodePopupCloseButton" type="button" class="close" data-dismiss="alert"><span class="glyphicon glyphicon-remove" style="font-size: 13px;"> </span> </div>';
                        htmlStr += '    <div class="nodePopupName">' + data['name'] + '</div>';
                        if (data['desc']) {
                            if (data['desc'].startsWith("http")) {
                                htmlStr += '    <a class="nodePopupLink" href="' + data['desc'] + '" target="_blank">Go to post..</a>';
                            }
                            else {
                                htmlStr += '    <div class="nodePopupDesc">' + data['desc'] + '</div>';
                            }
                        }
                        htmlStr += '    <div class="nodePopupGroup">GROUP: ' + data['groupId'] + '</div>';
                        htmlStr += '    <div class="nodePopupLeader">LEADER: ' + data['leaderId'] + '</div>';
                        htmlStr += '    <div class="nodePopupImage"><img src="' + d['image'] + '" style="width: 130px;" /></div>';
                        htmlStr += '</div>';

                        $("body").append(htmlStr);
                        $("#nodePopupCloseButton").click(removePopup);
                    }

                    showPopup(d);

                    mNode.filter(function (d1) {
                        return (d !== d1 && d1.adjacents.indexOf(d.id) == -1);
                    }).select("image").style("opacity", 0.2);
                    mNode.filter(function (d1) {
                        return (d !== d1 && d1.adjacents.indexOf(d.id) == -1);
                    }).select("circle").style("stroke", "#f6f6f6");
                    mLink.filter(function (d1) {
                        return (d !== d1.source && d !== d1.target);
                    }).style("opacity", 0.2);

                    mNode.filter(function (d1) {
                        return (d == d1 || d1.adjacents.indexOf(d.id) !== -1);
                    }).select("image").style("opacity", 1);
                    mNode.filter(function (d1) {
                        return (d == d1 || d1.adjacents.indexOf(d.id) !== -1);
                    }).select("circle").style("stroke", "gray");
                    mLink.filter(function (d1) {
                        return (d == d1.source || d == d1.target);
                    }).style("opacity", 1);
                })
                    .on('mouseout', function () {
                        // removePopup();
                        mNode.select("image").style("opacity", 1);
                        mNode.select("circle").style("stroke", "gray");
                        mLink.style("opacity", 1);
                    });

                var nodeCircle = mNode.append("circle")
                    .attr("r", function (d) {
                        return 0.5 * Math.max(d.width, d.height)
                    })
                    .attr("stroke", "gray")
                    .attr("stroke-width", "2px")
                    .attr("fill", "white");

                var nodeImage = mNode.append("image")
                    .attr("xlink:href", function (d) {
                        return d.image
                    })
                    .attr("height", function (d) {
                        return d.height + ""
                    })
                    .attr("width", function (d) {
                        return d.width + ""
                    })
                    .attr("x", function (d) {
                        return -0.5 * d.width
                    })
                    .attr("y", function (d) {
                        return -0.5 * d.height
                    })
                    .attr("clip-path", function (d) {
                        return "circle(" + (0.48 * Math.max(d.width, d.height)) + "px)"
                    });


                simulation.nodes(mNodesData);
                simulation.force(".edge").links(mEdgesData);

                simulation.on("tick", function () {
                    mLink.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;
                        })

                    mNode.attr("transform", function (d) {
                        return "translate(" + d.x + "," + d.y + ")"
                    });
                    mNode.attr("cx", function (d) {
                        return d.x = Math.max(d.width, Math.min(width - d.width, d.x));
                    })
                        .attr("cy", function (d) {
                            return d.y = Math.max(d.height, Math.min(height - heightDelta - d.height, d.y));
                        });
                });

                function dragstarted(d) {
                    if (!d3.event.active) simulation.alphaTarget(0.3).restart();
                    d.fx = d.x;
                    d.fy = d.y;
                }

                function dragged(d) {
                    d.fx = d3.event.x;
                    d.fy = d3.event.y;
                }

                function dragended(d) {
                    if (!d3.event.active) simulation.alphaTarget(0);
                    d.fx = null;
                    d.fy = null;
                }
            }
        }
    }

    function getData() {
        return $.ajax({
            url: 'api/v1/data.json',
            type: "GET",
        });
    }

    var graph = Graph('d3Graph');
    graph.init();

    $.when(getData()).then(function (data) {
        graph.addNodes(data.nodes);
        graph.addEdges(data.edges);
        graph.draw();

    });


    function add() {
        graph.addNodes([{
            "id": 4,
            "image": "images/4.jpg",
            "height": 20,
            "width": 20,
            "adjacents": [0],
            "data": {
                "name": "Number4",
                "groupId": "Bla4",
                "desc": "Desc4",
                "leaderId": "1234-1234"
            }
        }]);
        graph.addEdges([{
            "source": 4,
            "target": 3,
            "width": 1
        }])
        graph.draw();
    }

解决方案

As svg elements are layered in the order they are drawn, the last drawn element will be the topmost element. As you add links after the original drawing of the force, links will overlap nodes. Two solutions come to mind:

  1. Use .lower()

When appending a link, use selection.lower() to move it to the bottom (this moves the selected elements in the DOM so that they are under other elements):

svg.append("line")
  .attr(...)
  .lower();

  1. Use multiple g elements

Use one g for the links, append this one to the SVG first. Use a second g for the nodes. Now rather than appending links and nodes to the same selection (the svg selection), just append them to their respective g selection. The order in which the g elements are appended now dictates the layering of your nodes and links irrespective of the order they were added to the visualization.

这篇关于节点下方的D3 js链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆