我使用以下逻辑构建了下面的图表:

  • 将鼠标悬停在节点上 - 它是非连接节点并且它们的链接是透明的。
  • 将鼠标悬停在链接上 - 所有节点和链接都是透明的,除了触摸的链接(变为粗体)及其两个节点。

这非常有效,直到我尝试向图中添加更多节点。按添加节点按钮,添加另一个节点及其到聚会的链接。问题是,节点逻辑被破坏(链接逻辑仍然有效)。 知道为什么吗?

谢谢! JSFiddle

function removeNodePopup() { 
    $("#nodePopup").remove(); 
} 
 
function showNodePopup(node) { 
    removeNodePopup(); 
    if (!node['data']) { 
        return; 
    } 
 
    var data = node['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="' + node['image'] + '" style="width: 130px;" /></div>'; 
    htmlStr += '</div>'; 
 
    $("body").append(htmlStr); 
    $("#nodePopupCloseButton").click(removeNodePopup); 
} 
 
const LINK_DEFAULT_COLOR = "#ccc"; 
const NODE_DEFAULT_COLOR = "gray"; 
const DEFAULT_OPACITY = 1; 
const BACKGROUND_OPACITY = 0.2; 
 
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", LINK_DEFAULT_COLOR) 
                .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); 
        }, 
        onMouseOut: function () { 
            // removePopup(); 
            mNode.select("image").style("opacity", DEFAULT_OPACITY); 
            mNode.select("circle").style("stroke", NODE_DEFAULT_COLOR); 
            mLink.style("opacity", DEFAULT_OPACITY).style("stroke", LINK_DEFAULT_COLOR); 
        }, 
        draw: function () { 
            mNode = svg.selectAll(".node") 
                .data(mNodesData) 
                .enter() 
                .append("g") 
                .attr("class", "node"). 
                merge(mNode); 
 
            mLink = svg.selectAll(".edge") 
                .data(mEdgesData) 
                .enter() 
                .append("line") 
                .attr("class", "edge") 
                .style("stroke", LINK_DEFAULT_COLOR) 
                .style("stroke-width", function (e) { 
                    return 2 
                    /* e.width*/ 
                }).merge(mLink).lower(); 
 
            mNode.call(d3.drag() 
                .on("start", dragstarted) 
                .on("drag", dragged) 
                .on("end", dragended)); 
 
            mNode.on('mouseover', function (thisNode) { 
                showNodePopup(thisNode); 
                var thisNodeID = thisNode.id; 
                var connectedNodes = mEdgesData.filter(function(d) { 
                    return d.source.id === thisNodeID || d.target.id === thisNodeID 
                }).map(function(d) { 
                    return d.source.id === thisNodeID ? d.target.id : d.source.id 
                }); 
 
                mNode.each(function (otherNode, id) { 
                    var image = d3.select(this).select("image"); 
                    var circle = d3.select(this).select("circle"); 
                    if (connectedNodes.indexOf(otherNode.id) > -1 || thisNodeID == otherNode.id) { 
                        image.style("opacity", DEFAULT_OPACITY); 
                        circle.style("stroke", NODE_DEFAULT_COLOR); 
                    } 
                    else { 
                        image.style("opacity", BACKGROUND_OPACITY); 
                        circle.style("stroke", "#f6f6f6"); 
                    } 
                }); 
 
                // var filteredNodes = mNode.filter(function(otherNode) { 
                //     return connectedNodes.indexOf(otherNode.id) == -1 
                // }); 
                // 
                // filteredNodes.select("image").style("opacity", BACKGROUND_OPACITY); 
                // filteredNodes.select("circle").style("stroke", "#f6f6f6"); 
                // 
                // var unfilterdNode = mNode.filter(function (otherNode) { 
                //     return connectedNodes.indexOf(otherNode.id) > -1 || thisNodeID == otherNode.id; 
                // }); 
                // unfilterdNode.select("image").style("opacity", DEFAULT_OPACITY); 
                // unfilterdNode.select("circle").style("stroke", NODE_DEFAULT_COLOR); 
 
                mLink.filter(function (otherLink) { 
                    return (thisNode !== otherLink.source && thisNode !== otherLink.target); 
                }).style("opacity", BACKGROUND_OPACITY); 
 
                mLink.filter(function (otherLink) { 
                    return (thisNode == otherLink.source || thisNode == otherLink.target); 
                }).style("opacity", DEFAULT_OPACITY); 
            }) 
                .on('mouseout', this.onMouseOut); 
 
            mLink.on('mouseover', function (currentLink) { 
                mLink.filter(function (otherLink) { 
                    return (currentLink == otherLink); 
                }).style("stroke", "black"); 
                mLink.filter(function (otherLink) { 
                    return (currentLink !== otherLink); 
                }).style("opacity", BACKGROUND_OPACITY); 
 
                mNode.filter(function (otherNode) { 
                    return (currentLink.source != otherNode || currentLink.target != otherNode); 
                }).select("image").style("opacity", BACKGROUND_OPACITY); 
                mNode.filter(function (otherNode) { 
                    return (currentLink.source != otherNode || currentLink.target != otherNode); 
                }).select("circle").style("stroke", "#f6f6f6"); 
 
                mNode.filter(function (d1) { 
                    return (d1 == currentLink.source || d1 == currentLink.target); 
                }).select("image").style("opacity", DEFAULT_OPACITY); 
                mNode.filter(function (d1) { 
                    return (d1 == currentLink.source || d1 == currentLink.target); 
                }).select("circle").style("stroke", NODE_DEFAULT_COLOR); 
 
            }).on('mouseout', this.onMouseOut); 
 
            var nodeCircle = mNode.append("circle") 
                .attr("r", function (d) { 
                    return 0.5 * Math.max(d.width, d.height) 
                }) 
                .attr("stroke", NODE_DEFAULT_COLOR) 
                .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; 
            } 
        } 
    } 
} 
 
initialData = { 
    "nodes": [{ 
        "id": 0, 
        "image": "images/0.jpg", 
        "height": 40, 
        "width": 40, 
        "data": { 
            "name": "Number0", 
            "groupId": "Bla1", 
            "desc": "Desc1", 
            "leaderId": "123-123" 
        } 
    }, { 
        "id": 1, 
        "image": "images/1.jpeg", 
        "height": 100, 
        "width": 100, 
        "data": { 
            "name": "Number1", 
            "groupId": "Bla2", 
            "desc": "Desc1", 
            "leaderId": "123-123" 
        } 
    }, { 
        "id": 2, 
        "image": "images/2.png", 
        "height": 50, 
        "width": 50, 
        "data": { 
            "name": "Number2", 
            "groupId": "Bla3", 
            "desc": "Desc1", 
            "leaderId": "123-123" 
        } 
    }, { 
        "id": 3, 
        "image": "images/3.jpeg", 
        "height": 40, 
        "width": 40, 
        "data": { 
            "name": "Number3", 
            "groupId": "Bla4", 
            "desc": "Desc1", 
            "leaderId": "123-123" 
        } 
    }], 
    "edges": [{ 
        "source": 0, 
        "target": 1, 
        "width": 5, 
        "data": { 
            "counter": 500 
        } 
    }, { 
        "source": 0, 
        "target": 2, 
        "width": 10, 
        "data": { 
            "counter": 500 
        } 
    }, { 
        "source": 0, 
        "target": 3, 
        "width": 1, 
        "data": { 
            "counter": 500 
        } 
    }] 
}; 
 
 
var graph = Graph('d3Graph'); 
graph.init(); 
graph.addNodes(initialData.nodes); 
graph.addEdges(initialData.edges); 
graph.draw(); 
//add(); 
 
 
 
function add() { 
    graph.addNodes([{ 
        "id": 4, 
        "image": "images/4.jpg", 
        "height": 20, 
        "width": 20, 
        "data": { 
            "name": "Number4", 
            "groupId": "Bla4", 
            "desc": "Desc4", 
            "leaderId": "1234-1234" 
        } 
    }]); 
    graph.addEdges([{ 
        "source": 4, 
        "target": 3, 
        "width": 1, 
        "data": { 
            "counter": 500 
        } 
    }]) 
    graph.draw(); 
} 

请您参考如下方法:

jsfiddle

您多次调用了draw方法,因此您必须小心对待它。

只有新添加的节点才应该添加 imagecircle 标签, 所以你应该改变

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

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

并改变

var nodeCircle = mNode.append("circle") 

var nodeCircle = newNodes.append("circle") 

image 相关代码应该以相同的方式更改。


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!