当前位置: 首页 > 知识库问答 >
问题:

如何在D3.js基于力的标注布局图中获取公共子节点

丁翰海
2023-03-14

我正在使用D3进行web爬虫可视化,它使用了一个基于强制的标签图,如下面所示:基于强制的标签放置图

document.addEventListener('DOMContentLoaded', function () {
    drawVisual();
});

function drawVisual()
{

    var w = 960, h = 500;
    //var w = 1024, h = 768;

    //var vis = d3.select("#tab_5_contents").append("svg:svg").attr("width", w).attr("height", h);
    var vis = d3.select("#forcedLayoutGraph").append("svg:svg").attr("width", w).attr("height", h);

            var QueuedORG = [];
            //QueuedORG = JSON.parse(localStorage.getItem('storeArray'));
            QueuedORG.push({url: "Root", parentURL: "Root", used:0});
            QueuedORG.push({url: "a", parentURL: "Root"});
            QueuedORG.push({url: "b", parentURL: "Root"});
            QueuedORG.push({url: "c", parentURL: "Root"});
            QueuedORG.push({url: "d", parentURL: "Root"});
            QueuedORG.push({url: "e", parentURL: "a"});
            QueuedORG.push({url: "f", parentURL: "a"});
            QueuedORG.push({url: "g", parentURL: "a"});
            QueuedORG.push({url: "h", parentURL: "a"});
            QueuedORG.push({url: "p", parentURL: "b"});
            QueuedORG.push({url: "q", parentURL: "b"});
            QueuedORG.push({url: "r", parentURL: "b"});
            QueuedORG.push({url: "x", parentURL: "c"});
            QueuedORG.push({url: "y", parentURL: "x"});
            QueuedORG.push({url: "y", parentURL: "c"});
            QueuedORG.push({url: "x", parentURL: "a"});
            QueuedORG.push({url: "y", parentURL: "b"});


            var nodes = [];

            var labelAnchors = [];
            var labelAnchorLinks = [];
            var links = [];

            for(var i = 0; i < QueuedORG.length; i++) 
            {
                var nodeExists = 0;

                //check to see if a node for the current url has already been created. If yes, do not create a new node
                for(var j = 0; j < nodes.length; j++)  
                {
                    if(QueuedORG[i].url == nodes[j].label)
                        nodeExists = 1;

                }

                if (nodeExists == 0)
                {
                    var urlLabel = QueuedORG[i].url;
                    //remove 'http://' part
                    /*urlLabel = urlLabel.split("http://")[1];
                    if(urlLabel.match("www"))
                    urlLabel = urlLabel.split("www.")[1];
                    var rest = urlLabel.split("\.")[1];
                    urlLabel = urlLabel.split("\.")[0];*/

                    var node = {
                        label : QueuedORG[i].url,
                        category : QueuedORG[i].category
                    };
                    nodes.push(node);
                    labelAnchors.push({
                        node : node
                    });
                    labelAnchors.push({
                        node : node
                    });
                }
            };

            for(var i=0;i<nodes.length; i++)
            {
                console.log("node i:"+i+nodes[i]+"\n");
                console.log("labelAnchor i:"+i+labelAnchors[i]+"\n");
            }

            //To create links for connecting nodes
            for(var i = 0; i < QueuedORG.length; i++) 
            {
                var srcIndx = 0, tgtIndx = 0;
                for(var j = 0; j < nodes.length; j++)
                {
                    if( QueuedORG[i].url == nodes[j].label ) //to find the node number for the current url
                    {
                        srcIndx = j;
                    }

                    if( QueuedORG[i].parentURL == nodes[j].label ) //to find the node number for the parent url
                    {
                        tgtIndx = j;
                    }
                }
                //console.log("src:"+srcIndx+" tgt:"+tgtIndx);

                //connecting the current url's node to the parent url's node
                links.push({
                    source : srcIndx,
                    target : tgtIndx,
                    weight : 1,
                });

                labelAnchorLinks.push({
                    source : i * 2,
                    target : i * 2 + 1,
                    weight : 1
                });
            };

            var force = d3.layout.force().size([w, h]).nodes(nodes).links(links).gravity(1).charge(-10000).linkStrength(function(x) {
                return x.weight * 10                                            // charge is for inter-node repel, link distance is node-node distance 
            });
            force.linkDistance(function(d) {
                return d.weight * 100;
            });

            force.start();

            var force2 = d3.layout.force().nodes(labelAnchors).links(labelAnchorLinks).gravity(0).linkStrength(10).charge(-500).size([w, h]);   //charge is for inter-label repel, link distance is node-label distance
            force2.linkDistance(function(d) {
                return d.weight * 10;
            });

            force2.start();

            var link = vis.selectAll("line.link").data(links).enter().append("svg:line").attr("class", "link").style("stroke", "#CCC");

            var colors = {"1": "black", "2": "blue", "3": "red"};           // 1=root node 2=blog nodes 3=.org nodes
            var shape = {"1": "diamond", "2": "cross", "3": "circle"};

            var node = vis.selectAll("g.node").data(force.nodes()).enter().append("path").attr("class", "node").call(force.drag);
        //node.append("circle").attr("r", 5).style("stroke", "#FFF").style("stroke-width", 3).attr("class", function(d) {return "node category"+d.category});

            node.attr("d", d3.svg.symbol().type(function(d) {return shape[d.category];})).style("stroke", "#FFF").style("fill", function(d){ return colors[d.category];});

            var anchorLink = vis.selectAll("line.anchorLink").data(labelAnchorLinks)//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999");

            var anchorNode = vis.selectAll("g.anchorNode").data(force2.nodes()).enter().append("svg:g").attr("class", "anchorNode");
            anchorNode.append("svg:circle").attr("r", 0).style("fill", "#FFF");
            anchorNode.append("svg:text").text(function(d, i) {
                return i % 2 == 0 ? "" : d.node.label
            }).style("fill", "#555").style("font-family", "Arial").style("font-size", 12);

            var updateLink = function() {
                this.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;
                });
            }

            var updateNode = function() {
                this.attr("transform", function(d) {
                    return "translate(" + d.x + "," + d.y + ")";
                });

            }

            force.on("tick", function() {

                force2.start();

                node.call(updateNode);

                anchorNode.each(function(d, i) {
                    if(i % 2 == 0) {
                        d.x = d.node.x;
                        d.y = d.node.y;
                    } else {
                        var b = this.childNodes[1].getBBox();

                        var diffX = d.x - d.node.x;
                        var diffY = d.y - d.node.y;

                        var dist = Math.sqrt(diffX * diffX + diffY * diffY);

                        var shiftX = b.width * (diffX - dist) / (dist * 2);
                        shiftX = Math.max(-b.width, Math.min(0, shiftX));
                        var shiftY = 5;
                        this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")");
                    }
                });

                anchorNode.call(updateNode);

        link.call(updateLink);
        anchorLink.call(updateLink);

    });
}

共有1个答案

长孙嘉
2023-03-14

问题是您组装LabelAnchorLinks的方式。通过使用索引i*2i*2+1,假设每个i有两个节点。只有当queuedorg中的所有内容都表示一个新节点时,这才是真的。

若要修复,请使用源节点的索引而不是i:

labelAnchorLinks.push({
    source : srcIndex * 2,
    target : srcIndex * 2 + 1,
    weight : 1
});
 类似资料:
  • 我刚刚开始学习JavaFX来构建桌面应用程序,目前还没有任何个人培训。现在关于这个问题,我正在尝试做一个自定义布局,它的大小取决于它的孩子的整体大小。我的问题是在计算高度和宽度时得到每个孩子的尺寸。这里,我使用< code>getLayoutBounds()方法来检索孩子的尺寸,但是在我的例子中,它总是返回0: 所以我想这是关于布局传递的(比如说,孩子还没有布局)。但是不管怎样,如果这里是不是这样

  • 基本上,我正在尝试从特定的子reddit中获取随机图片的URL。我尝试过在这里使用原始JSON,但我不能完全弄清楚。我一直在使用snekfetch来获取JSON,因为它以前在不太复杂的网站上工作过,但是我已经看到了其他方法,如超级代理和snoowrap,我不知道如何正确使用。以下是我尝试使用snekfetch的方法(我正在尝试将其合并到不和谐的机器人中): 我是JSON的新手,所以如果这段代码充满

  • 本文向大家介绍JS 获取HTML标签内的子节点的方法,包括了JS 获取HTML标签内的子节点的方法的使用技巧和注意事项,需要的朋友参考一下 子节点的个数: 注意: 标签开/闭合算2个节点 第几个子几点: 示例: 这里是 length-4 处,margin-left:20px 输出:length=8 实例: 以上就是小编为大家带来的JS 获取HTML标签内的子节点的方法的全部内容了,希望对大家有所帮

  • 一个灵活的力导向图布局实现使用位置Verlet整合算法允许简单地控制。有关物理模拟的更多信息,请参见Thomas Jakobsen。这个实例是利用四叉树加速电荷相互作用使用Barnes–Hut approximation。除了电荷charge力,pseudo-gravity力保持节点中心在可见区域并且避免排出断开子图,当链接的固定距离的几何约束时。额外的自定义力和约束可应用于"tick" 事件,简

  • 问题内容: 我希望力导向布局中的某些节点忽略所有力,并基于该节点的属性停留在固定位置,同时仍能够拖动其他节点并对其施加排斥力并保持其链接线。 我以为就这么简单: 我也尝试过手动设置每个刻度的节点的x和y属性,但是如果该节点受力影响,链接将继续浮动到该节点所在的位置。 显然,我对这应该如何工作有基本的误解。如何在固定链接的同时仍允许它们可拖动的同时将节点固定在一个位置? 问题答案: 在所需的节点上将

  • 我想出了一个蛮力算法来寻找两个给定字符串之间最长的公共子序列。它看起来时间复杂度为O(n^3)。它通过了我所有的测试用例,但我仍然不确定它是否会通过所有的测试用例......请让我知道这是正确的蛮力算法? 如果上面的代码不对,我要蛮力算法返回最长的公共子序列字符串,,我怎么才能做到这一点???