d3.js-添加新节点后图形被破坏 [英] d3.js - graph is broken after adding new nodes

查看:83
本文介绍了d3.js-添加新节点后图形被破坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下逻辑构建以下图形:

I build the graph below with the following logic:

  • 将鼠标悬停在节点上-它是未连接的节点&它们的链接是透明的.
  • 将鼠标悬停在链接上-所有节点&链接是透明的,除了触摸的链接(变为粗体)和两个节点.

这很好,直到我尝试向图中添加更多节点.按下添加节点按钮,添加另一个节点,并链接到该聚会.问题在于,节点逻辑已损坏(链接逻辑仍然有效). 知道为什么吗?

That works great, until I try to add more nodes to the graph. Press on the Add Node button, adds another node and it's link to the party. The problem is, that the node logic is broken (the link logic still work). Any idea why?

谢谢! 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方法,因此必须谨慎对待.

You called draw method multiple times, so you have to treat it carefully.

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

Only newly added nodes are supposed to be added image and circle tags, so you should change

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相关代码应该以相同的方式更改.

And image related code are supposed to be changed in same manner.

这篇关于d3.js-添加新节点后图形被破坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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