d3 js重绘图再次添加现有节点

时间:2017-12-13 21:47:59

标签: d3.js

尝试使用add函数向现有图表添加新节点,最后使用所有新图表。这是我的code

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));
        },
        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*/
                });

            mNode = svg.selectAll(".node")
                .data(mNodesData)
                .enter()
                .append("g")
                .attr("class", "node")
                .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.jpeg",
        "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();
    // graph.draw();
}

如果我在页面上调用add原始图形堆栈,而在另一个边缘调用新的图形堆栈。节点已添加。我该如何做到这一点? (更新旧版本而不创建全新的..

3 个答案:

答案 0 :(得分:0)

您目前拥有的内容:

 mLink = svg.selectAll("link")
            .data(mEdgesData)
            .enter()
            .append("line")

通常selectAll("link")表示您选择所有链接的html元素。但是您附加了line而不是link。因此,附加元素不是selectAll的一部分。没有可能知道你只想将数据添加到已经存在的东西中。

答案 1 :(得分:0)

解决方案是将merge添加到两个链接&amp;节点:

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);

答案 2 :(得分:0)

当我尝试为具有动态数据的图形创建常规更新过程时,我遇到了类似的问题。在更新节点或链接时,将触发select address from tab where address like '%VIA%BOEZIO%6%' 函数。

这个想法的工作原理如下;重新绘制图形时(即数据更改时),所有旧节点和链接都将被删除并重新绘制。使用redraw,节点保持在原位。

这是我的工作示例

.join()

在我的redraw = () => { simulation.nodes(nodes); simulation.force('link') .links(links) .initialize(nodes); d3.selectAll('g.node').remove(); // remove all old nodes d3.selectAll('g.node').data(nodes).join(); d3.selectAll("line").data(links).join(); draw(); simulation.alpha(0.1) simulation.restart(); } 函数中,将相应地创建节点和链接:

draw()

draw = () => { container.selectAll('line').data(links).join('line'); // creates nodes with rectangles that contain text container.selectAll('g.node').raise() .data(nodes).join("g") .each(function (d, i) { d3.select(this).append("rect"); var text = d3.select(this).append("text").text(d => d.name) // calculate text width for function tick() to adapt rect x position d.width = text.filter(t => t.index == d.index).node() .getBBox().width; }) .call(drag(simulation)); } 是可缩放和可拖动的SVG元素:

container

为完整起见,这是我的container = svg.append('g'); svg.call(d3.zoom() .on('zoom', () => this.container.attr('transform', d3.event.transform)) .scaleExtent([0.25, 2])) 函数:

tick()

如果有时间,我稍后再发布一个JSFiddle。