将新节点添加到力导向布局

2024-02-26

关于 Stack Overflow 的第一个问题,请耐心等待!我是 d3.js 的新手,但一直对其他人能够用它完成的事情感到惊讶......并且几乎同样对我自己用它取得的进展如此之少感到惊讶!显然我没有摸到什么,所以我希望这里善良的灵魂可以向我展示光明。

我的目的是创建一个可重用的 javascript 函数,它只执行以下操作:

  • 在指定的 DOM 元素中创建空白的力导向图
  • 允许您向该图形添加和删除带标签的、带有图像的节点,并指定它们之间的连接

我已经采取了http://bl.ocks.org/950642 http://bl.ocks.org/950642作为一个起点,因为这本质上是我希望能够创建的布局:

我的代码如下所示:

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript" src="underscore-min.js"></script>
    <script type="text/javascript" src="d3.v2.min.js"></script>
    <style type="text/css">
        .link { stroke: #ccc; }
        .nodetext { pointer-events: none; font: 10px sans-serif; }
        body { width:100%; height:100%; margin:none; padding:none; }
        #graph { width:500px;height:500px; border:3px solid black;border-radius:12px; margin:auto; }
    </style>
</head>
<body>
<div id="graph"></div>
</body>
<script type="text/javascript">

function myGraph(el) {

    // Initialise the graph object
    var graph = this.graph = {
        "nodes":[{"name":"Cause"},{"name":"Effect"}],
        "links":[{"source":0,"target":1}]
    };

    // Add and remove elements on the graph object
    this.addNode = function (name) {
        graph["nodes"].push({"name":name});
        update();
    }

    this.removeNode = function (name) {
        graph["nodes"] = _.filter(graph["nodes"], function(node) {return (node["name"] != name)});
        graph["links"] = _.filter(graph["links"], function(link) {return ((link["source"]["name"] != name)&&(link["target"]["name"] != name))});
        update();
    }

    var findNode = function (name) {
        for (var i in graph["nodes"]) if (graph["nodes"][i]["name"] === name) return graph["nodes"][i];
    }

    this.addLink = function (source, target) {
        graph["links"].push({"source":findNode(source),"target":findNode(target)});
        update();
    }

    // set up the D3 visualisation in the specified element
    var w = $(el).innerWidth(),
        h = $(el).innerHeight();

    var vis = d3.select(el).append("svg:svg")
        .attr("width", w)
        .attr("height", h);

    var force = d3.layout.force()
        .nodes(graph.nodes)
        .links(graph.links)
        .gravity(.05)
        .distance(100)
        .charge(-100)
        .size([w, h]);

    var update = function () {

        var link = vis.selectAll("line.link")
            .data(graph.links);

        link.enter().insert("line")
            .attr("class", "link")
            .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; });

        link.exit().remove();

        var node = vis.selectAll("g.node")
            .data(graph.nodes);

        node.enter().append("g")
            .attr("class", "node")
            .call(force.drag);

        node.append("image")
            .attr("class", "circle")
            .attr("xlink:href", "https://d3nwyuy0nl342s.cloudfront.net/images/icons/public.png")
            .attr("x", "-8px")
            .attr("y", "-8px")
            .attr("width", "16px")
            .attr("height", "16px");

        node.append("text")
            .attr("class", "nodetext")
            .attr("dx", 12)
            .attr("dy", ".35em")
            .text(function(d) { return d.name });

        node.exit().remove();

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

          node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
        });

        // Restart the force layout.
        force
          .nodes(graph.nodes)
          .links(graph.links)
          .start();
    }

    // Make it all go
    update();
}

graph = new myGraph("#graph");

// These are the sort of commands I want to be able to give the object.
graph.addNode("A");
graph.addNode("B");
graph.addLink("A", "B");

</script>
</html>

每次我添加一个新节点时,它都会重新标记所有现有节点;这些东西堆积在一起,事情开始变得丑陋。我明白这是为什么:因为当我打电话时update()添加新节点后,它会执行以下操作:node.append(...)到整个数据集。我不知道该怎么做仅我要添加的节点...而且我显然只能使用node.enter()创建一个新元素,因此这不适用于我需要绑定到节点的其他元素。我怎样才能解决这个问题?

感谢您就该问题提供的任何指导!

编辑是因为我很快修复了前面提到的几个其他错误的来源


经过长时间无法正常工作后,我终于偶然发现了一个演示,我认为该演示与任何文档都没有链接:http://bl.ocks.org/1095795 http://bl.ocks.org/1095795:

这个演示包含了最终帮助我解决问题的密钥。

在一个对象上添加多个对象enter()可以通过分配来完成enter()到一个变量,然后附加到该变量上。这是有道理的。第二个关键部分是节点和链接数组必须基于force()-- 否则,随着节点的删除和添加,图形和模型将不同步。

这是因为如果构造一个新数组,它将缺少以下内容属性 https://github.com/mbostock/d3/wiki/Force-Layout#nodes:

  • index - 节点数组中节点的从零开始的索引。
  • x - 当前节点位置的 x 坐标。
  • y - 当前节点位置的 y 坐标。
  • px - 前一个节点位置的 x 坐标。
  • py - 前一个节点位置的 y 坐标。
  • fixed - 一个布尔值,指示节点位置是否被锁定。
  • 权重 - 节点权重;关联链接的数量。

调用时并不严格需要这些属性force.nodes() https://github.com/mbostock/d3/wiki/Force-Layout#wiki-nodes,但如果这些不存在,那么它们将是randomly初始化为force.start() https://github.com/mbostock/d3/wiki/Force-Layout#wiki-start在第一次通话时。

如果有人好奇,工作代码如下所示:

<script type="text/javascript">

function myGraph(el) {

    // Add and remove elements on the graph object
    this.addNode = function (id) {
        nodes.push({"id":id});
        update();
    }

    this.removeNode = function (id) {
        var i = 0;
        var n = findNode(id);
        while (i < links.length) {
            if ((links[i]['source'] === n)||(links[i]['target'] == n)) links.splice(i,1);
            else i++;
        }
        var index = findNodeIndex(id);
        if(index !== undefined) {
            nodes.splice(index, 1);
            update();
        }
    }

    this.addLink = function (sourceId, targetId) {
        var sourceNode = findNode(sourceId);
        var targetNode = findNode(targetId);

        if((sourceNode !== undefined) && (targetNode !== undefined)) {
            links.push({"source": sourceNode, "target": targetNode});
            update();
        }
    }

    var findNode = function (id) {
        for (var i=0; i < nodes.length; i++) {
            if (nodes[i].id === id)
                return nodes[i]
        };
    }

    var findNodeIndex = function (id) {
        for (var i=0; i < nodes.length; i++) {
            if (nodes[i].id === id)
                return i
        };
    }

    // set up the D3 visualisation in the specified element
    var w = $(el).innerWidth(),
        h = $(el).innerHeight();

    var vis = this.vis = d3.select(el).append("svg:svg")
        .attr("width", w)
        .attr("height", h);

    var force = d3.layout.force()
        .gravity(.05)
        .distance(100)
        .charge(-100)
        .size([w, h]);

    var nodes = force.nodes(),
        links = force.links();

    var update = function () {

        var link = vis.selectAll("line.link")
            .data(links, function(d) { return d.source.id + "-" + d.target.id; });

        link.enter().insert("line")
            .attr("class", "link");

        link.exit().remove();

        var node = vis.selectAll("g.node")
            .data(nodes, function(d) { return d.id;});

        var nodeEnter = node.enter().append("g")
            .attr("class", "node")
            .call(force.drag);

        nodeEnter.append("image")
            .attr("class", "circle")
            .attr("xlink:href", "https://d3nwyuy0nl342s.cloudfront.net/images/icons/public.png")
            .attr("x", "-8px")
            .attr("y", "-8px")
            .attr("width", "16px")
            .attr("height", "16px");

        nodeEnter.append("text")
            .attr("class", "nodetext")
            .attr("dx", 12)
            .attr("dy", ".35em")
            .text(function(d) {return d.id});

        node.exit().remove();

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

          node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
        });

        // Restart the force layout.
        force.start();
    }

    // Make it all go
    update();
}

graph = new myGraph("#graph");

// You can do this from the console as much as you like...
graph.addNode("Cause");
graph.addNode("Effect");
graph.addLink("Cause", "Effect");
graph.addNode("A");
graph.addNode("B");
graph.addLink("A", "B");

</script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将新节点添加到力导向布局 的相关文章

  • 如何检测浏览器是否支持自定义元素

    我正在查看 Modernizr 它应该有助于功能检测 这应该可以帮助确定您的网站是否与给定的 Web 浏览器兼容 但我没有看到任何表明我可以使用它来检测自定义 HTML 的内容我们在内容中创建和定义的元素 如果不是 Modernizr 我如
  • 了解设置 JQuery 变量

    了解设置 JQuery 变量 最近 我通过在 StackOverflow 上遇到的另一个问题寻找帮助 了解到如何设置 JQuery 变量 如下所示 您可以通过简单地调用变量来创建输入字段 并且锚变量似乎也定义了样式 var clicked
  • 为什么 JavaScript base-36 转换看起来不明确

    我目前正在编写一段使用 Base 36 编码的 JavaScript 我遇到了这个问题 parseInt welcomeback 36 toString 36 看来要回归了 welcomebacg 我在 Chrome 开发者控制台和 Nod
  • 尝试将布尔 C# 变量传递给 javascript 变量并将其设置为 true

    在我的 aspx 页面中 我将布尔变量 C 传递给需要布尔类型的 javascript 函数 但遇到了问题 但是 C 变量返回 True 而 javascript 不喜欢大写 myjavascript 如果我将 c 变量转换为字符串 那么我
  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 解析“流”JSON

    我在浏览器中有一个网格 我想通过 JSON 将数据行发送到网格 但浏览器应该在接收到 JSON 时不断解析它 并在解析时将行添加到网格中 换句话说 在接收到整个 JSON 对象后 不应将行全部添加到网格中 应该在接收到行时将其添加到网格中
  • 使用模数按字母顺序对列表进行排序

    我在获取元素列表并按字母顺序对它们进行排序方面没有任何问题 但我很难理解如何使用模数来做到这一点 更新 这是按我的方式工作的代码 但是 我更喜欢下面提供的答案的可重用性 因此接受了该答案
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 使用 JavaScript 使链接保持活动状态并在单击时显示悬停效果

    I am struggling to make this work I d like to make it where if O F is clicked the hover state stays active if another li
  • 检查 JavaScript 字符串是否为 URL

    JavaScript 有没有办法检查字符串是否是 URL 正则表达式被排除在外 因为 URL 很可能是这样写的stackoverflow 也就是说它可能没有 com www or http 如果你想检查一个字符串是否是有效的 HTTP UR
  • 如何抑制窗口鼠标滚轮滚动...?

    我正在开发嵌入页面中的画布应用程序 我有它 因此您可以使用鼠标滚轮放大绘图 但不幸的是 这会滚动页面 因为它是文章的一部分 当我在 dom 元素上滚动鼠标滚轮时 是否可以阻止鼠标滚轮在窗口上滚动 附加鼠标滚轮 不是 Gecko DOMMou
  • 如何监听 jQuery AJAX 请求?

    以下两种实现 ajaxRequest 1 2 的方法应该是等效的 话说回来 为什么验证回调已执行的单元测试 3 在 1 中成功而在 2 中失败 我应该如何重写测试 3 来监视 2 中的成功回调 如果我尝试stub jQuery ajax使用
  • Meteor - 从客户端取消服务器方法

    我正在通过服务器方法执行数据库计数 用户可以选择他们希望如何执行计数 然后调用该方法 我的问题是 计数可能需要一些时间 并且用户可能会在方法运行时改变主意并请求不同的计数 有什么方法可以取消调用的方法并运行新的计数吗 我认为 this un
  • 跟踪用户何时点击浏览器上的后退按钮

    是否可以检测用户何时单击浏览器的后退按钮 我有一个 Ajax 应用程序 如果我可以检测到用户何时单击后退按钮 我可以显示适当的数据 任何使用 PHP JavaScript 的解决方案都是优选的 任何语言的解决方案都可以 只需要我可以翻译成
  • 表单计算器脚本基本价格未加载 OnLoad

    我的表单中有一个计算器来计算我的下拉选项选择 function select calculate on change calc input type checkbox calculate on click calc function cal
  • Grails 在 javascript 内的 GSP 站点中使用 grails var

    我有一个在 GSP 文件中的 javascript 代码中使用 grails 变量值的问题 例如 我有一个会话值session getAttribute selectedValue 我想在 javascript 代码部分使用这个值 我现在的
  • 如何使用tampermonkey模拟react应用程序中的点击?

    我正在尝试使用 Tampermonkey 脚本模拟对 React 元素的点击 不幸的是 由于 React 有自己的影子 DOM 所以天真的方法使用document querySelector 不工作 我遇到了一些需要修改 React 组件本
  • Laravel 中只向登录用户显示按钮

    如果我以 John 身份登录 如何才能只显示 John 的红色按钮而不显示 Susan 的红色按钮 测试系统环境 Win10 Laravel5 4 Mysql5 7 19 table class table table responsive
  • 为什么在 Internet Explorer 中访问 localStorage 对象会引发错误?

    我正在解决一个客户端问题 Modernizr 意外地没有检测到对localStorageInternet Explorer 9 中的对象 我的页面正确使用 HTML 5 文档类型 并且开发人员工具报告该页面具有 IE9 的浏览器模式和 IE
  • HTML 离线应用程序缓存,列出下载的文件

    作为我正在构建的离线 Web 应用程序的加载屏幕的一部分 使用缓存清单 http developer apple com library safari documentation iPhone Conceptual SafariJSData

随机推荐

  • Unity 5.4.2f-GVR13 中的 Daydream 非 VR 模式 [重复]

    这个问题在这里已经有答案了 上周我尝试将我的 Unity 项目集成到 Daydream 集成进展顺利 现在我试图将第一个场景 包括登录过程 所以我需要 android 软键盘 与应用程序的其余部分分开 我希望应用程序像任何 android
  • 在 C# 中记录对象的所有属性。如何记录内部对象属性?

    我试图 1 记录对象的所有属性 以及 2 其中特定对象类型的所有属性 我可以做 1 但不能做 2 现在就是这种情况 foreach PropertyDescriptor descriptor in TypeDescriptor GetPro
  • 当查询使用包含时,Rails 如何处理 has_many?

    如果我有一个包含许多帖子的用户模型 那么在以下场景中 Rails 将对数据库执行多少个查询 class User has many posts this is the main method in question def has post
  • msysGit:为什么git日志输出空行?

    当我在终端窗口底部键入命令时 插入的空白行似乎越少 如果我在终端窗口的顶部输入它 它会插入几乎整个窗口高度的空白行 如果我在最底部键入它 则不会插入空行 看起来分页程序正在将输出推送到终端窗口的底部 但我希望输出位于我的命令的正下方或顶部
  • 如何检查是否隐式生成了移动构造函数?

    我有几个类 我希望检查是否正在生成默认移动构造函数 有没有办法检查这一点 无论是编译时断言 还是解析生成的目标文件 或者其他 励志例子 class MyStruct public ComplicatedBaseClass std vecto
  • 如何构建、分区和构建大型 MVC 应用程序以便以小的增量片段进行部署?

    我们将开发一个非常大的垂直市场 Web 应用程序 并且倾向于 MVC 方法 它将有 1 个应用程序中所有视图共用的母版页 主控会为整个应用提供一个导航 搜索框架 这将允许用户搜索和选择实体 然后导航到要执行的功能 数据库模型将有 700 到
  • 不能使用公共嵌套类作为私有方法参数

    在下面的代码中 class Outer private void f private Outer Inner in Wrong public class Inner void f public Outer Inner in OK f pri
  • 如何保证 OAuth 消费者秘密的安全,以及当其泄露时如何反应?

    这个问题是关于尝试了解在 Android 等移动平台上实现 oauth 所涉及的安全风险 这里假设我们有一个 Android 应用程序 其代码中嵌入了消费者密钥 秘密 假设消费者的秘密被泄露 并且黑客已经掌握了它 那么会产生什么后果 消费者
  • Debian平台上如何使用pm2启动命令?

    以下是 GitHub 上文档的链接 https github com Unitech pm2 startup script Generation pm2 startup https github com Unitech pm2 startu
  • 当变量为 Null 时 Laravel 5.3 验证失败

    自从 Laravel 从 5 1 升级到 5 3 以来 我在验证方面遇到了一些奇怪的问题 当我发布这样的数据时 firstName null 验证规则是这样的 validator Validator make postData firstN
  • 在 Flask 中迭代提交的表单字段?

    在 Flask 0 8 中 我知道我可以使用以下方式访问各个表单字段form fieldname data 但是有没有一种简单的方法来迭代所有表单字段 我正在构建一个电子邮件正文 我想循环所有字段并为每个字段创建一个字段名称 值条目 而不是
  • 需要在 C 中将 2 的补码转换为十进制的最快方法

    我有 32 位内的某个 18 位 2 的补码 我需要将它们转换为十进制 请给我看一段 C 代码片段 首先你需要做符号扩展 http en wikipedia org wiki Sign extension在你的18位上 填写本机int co
  • svn:数据库已锁定,正在执行语句“RELEASE s0”

    在尝试从私有分支进行合并时 我不断收到列出的错误 数据库被锁定 正在执行语句 RELEASE s0 我运行 collabnet subversion 边缘服务器 1 7 5 3220 94 我运行tortoise svn客户端 Tortoi
  • 创建如果两个表中的行匹配条件则返回 id 的查询

    我正在学习 SQL dbms 并使用 Postgres 我想返回在特定列中都具有特定值的行 例如在表格中Carpets and Curtains 我想得到ids 行 其中颜色为 light yellow 我想我需要加入 但不确定是什么类型
  • 如何在 OpenLayers 5.3.0 中剪切和显示剪切的向量几何

    我必须根据主 限制向量层来剪辑向量层 绘制时 如果绘制图层的某些部分在限制图层之外 则剪掉限制图层之外的区域 示例 1 正如我们所看到的 底部边框的一部分处于限制之外 紫色层 我想知道是否可以向限制层外部的剪辑区域添加功能 示例 2 删除限
  • C 标准数据结构库? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找 C 语言 Windows 平台 中经过测试和测试的标准库 它实现了堆栈 队列 树等数据结构
  • 错误:“函数”对象不可下标

    我正在做我的 python 作业 但是当我想测试上面的情况时出现错误 这是我的代码 def evalTerm env t if type t Node for label in t children t label if label Num
  • 安全共享的 Google 日历

    我正在开发一个小型网站 它有一个非常简单的想法 有两组用户 办公室和工人 都必须登录才能访问该网站 该网站是使用Zend框架构建的 问题 我想要一个所有用户都可以访问的日历 办公室工作人员能够编辑日历 而工作人员只能查看日历 我真的很想使用
  • 如何利用MVC中的常用图像资源

    我有几个 ASP NET MVC3 和 4 网站 所有站点都使用独立于库的相同资源 资源是 resx 文件 我想在这些网站内的 html 中使用这些资源中的图像 我之前没有使用过 resx 文件 所以不确定使用它们的好方法是什么 我认为我可
  • 将新节点添加到力导向布局

    关于 Stack Overflow 的第一个问题 请耐心等待 我是 d3 js 的新手 但一直对其他人能够用它完成的事情感到惊讶 并且几乎同样对我自己用它取得的进展如此之少感到惊讶 显然我没有摸到什么 所以我希望这里善良的灵魂可以向我展示光