如何在d3.js中创建家谱树?

68
我目前正在进行一个小型的家谱实验,并希望实现像下图一样简单的家谱树。
到目前为止,最好的搜索结果只能提供孩子只能有父节点的示例。但我需要创建实体之间的链接(从父亲到母亲)以及节点和其他链接之间的链接(从孩子到父母链接)。目前我没有固定的数据架构。
我选择了d3.js来完成这个任务因为它看起来能够胜任。我只是不知道如何开始或甚至从哪里开始。关于d3.js的教程仅涵盖标准图表,如条形图。
我希望有人能帮助我解决这个问题。

This is how the result should look like


2
一个标准的层次结构表就可以了。你尝试过什么? - Pogrindis
3
这里有两个问题:创建和呈现家谱图。D3.js专注于渲染。你需要一个图形数据结构来保存数据。 - duffymo
1
嗨 @prc322,我不确定你是否可以直接在这里提供帮助。但是在我的项目(http://arda-maps.org/familytree/)中,我遇到了同样的麻烦。首先,是的,在D3中没有现成的家谱布局可用。因此,我花费了很长时间寻找一个好的替代方案。但不幸的是,并没有找到。也许力导向布局对你来说也是一种好方法。我不认为它肯定是最好的,但至少它显示了所有必要的连接。随意单击“Show All”按钮,以了解大约400个节点的情况。=)希望对你有所帮助。 - kwoxer
1
你可以看一下dagre-d3。它基本上是一个绘制有向无环图的库。因此,您应该能够使用它来绘制家谱树。这里是一个dagre-d3图的示例。 - Baz
2
我联系了原作者。如果他在6天内没有回复,我仍然可以提供答案,但我希望他能回复,因为他值得。无论如何:不用谢! - ChrLipp
显示剩余13条评论
7个回答

49

我的方法如下:

让我们以您在附图中所示的例子为例:

Jenny Of Oldstones 也是 Aegon V 的孩子,但这个孩子和其他 Aegon V 的孩子不同之处在于,在这种情况下,我没有绘制它们之间的链接。

这是通过在节点JSON中将节点设置为no_parent: true来完成的。例如:

//Here Q will not have a parent
 {
            name: "Q",
            id: 16,
            no_parent: true
 }
在代码中检查_elbow函数,它的作用是不绘制它与父级之间的线条:

在代码中检查_elbow函数,它的作用是不绘制它与父级之间的线条:

if (d.target.no_parent) {
    return "M0,0L0,0";
}

下一个场景是链接连接着节点 Aerys II 和 Rahella,该节点有一组子节点。

  • 我创建了一个标记为hidden: true的节点
  • 我将这个节点的display:none。看起来子节点是从节点Aerys II和Rahella之间的线条中出现的。

JSON示例:

//this node will not be displayed
{ name: "",
    id: 2,
    no_parent: true,
    hidden: true,
    children: [....]

    }
在代码中,检查我创建矩形的位置,下面的代码隐藏了该节点:
    .attr("display", function (d) {
    if (d.hidden) {
        return "none"
    } else {
        return ""
    };
})

完整的代码在这里:http://jsfiddle.net/cyril123/0vbtvoon/22/

在上面的例子中,我使用节点名称A/B/C等,但您可以根据自己的需求进行更改。您需要将文本居中。

我已经向代码添加了注释以帮助您了解流程。如果您有任何不清楚的地方,请留言,我很乐意澄清。


如果您查看原始问题中的评论,那么您会发现有人链接了一个我想标记为正确的答案。我改变了主意:您的答案是最好的答案,因为它考虑了其他人没有考虑到的一些问题。谢谢! - user659025
1
@prc322 是的,我在编写这个答案之前已经阅读了那些评论。 - Cyril Cherian
首先感谢这种方法。您是否考虑过,如果在两个父代之间(例如在我的案例中,是指植物),在超过一代之后是否会交叉。您的方法在某些情况下有效,当子代附加在较低一代的父代之后。但在某些情况下,上一代的父代被拉到较低的X方向,图像就错位了。任何帮助都将不胜感激。 - dhirajbasukala
这是一个很好的答案,感觉棒极了。过去三天我一直在跟着最佳答案中的jsfiddle,最终成功了。非常感激您 :) - Codesingh
你好,能帮忙在后端实现这个东西吗?我的意思是我想在 API 中处理这个东西,这样当 JSON 数据来的时候,我可以直接将它添加到前端代码中, voila。再次感谢你提供这样一个棒极了的答案 :) - Codesingh
显示剩余4条评论

24

dTree是一款基于D3构建的开源库,用于创建家谱图(或类似的分层图)。

它处理手动生成D3图形的繁琐部分,并使用简单的JSON数据格式:

[{
  name: "Father",
  marriages: [{
    spouse: {
      name: "Mother",
    },
    children: [{
      name: "Child",
    }]
  }]
}]

如果您有兴趣进行修改,它支持回调用于节点渲染和事件处理。最后,该库截至2016年仍在开发中,欢迎提交拉取请求。

声明:我是dTree的作者。我在像您一样搜索网络并找不到我喜欢的东西后创建了该库。


1
这太棒了,谢谢分享。我只是在玩创建自己家谱的想法,这非常有帮助。 - LocustHorde
1
谢谢分享!如果有一个选项可以将树水平或垂直渲染,那就太好了! - Hasan Sh
谢谢,正是我要找的。 - Adrian

10

不太好的消息: 我所做的研究表明,没有直接实现这一功能的开箱即用的d3库而不需要一些自定义。

好消息: 已经有其他人研究过这个问题,并找到了一些很好的起点!我意识到这并不是整个任务的完整解决方案,但是从你的问题中可以看出,迄今为止你遇到的主要困难就是弄清楚从哪里开始(例如,“关于d3.js的教程仅涵盖标准图表,如条形图。”)。在没有更好的东西的情况下,我至少会回应这一部分。

首先,作为对此相关stackoverflow帖子的回复,inanutshellus提供了一些非常棒的d3工具,这些工具可供使用并可能在此处有用。稍加自定义/扩展,他们应该能够相对快速地帮助您达到目标。为了永存的目的,在此再次列出inanutshellus的答案:

有一些选项,但我认为每个选项都需要一些工作。如果在JSON中有一个单一的表示家谱的标准将会很有帮助。我最近注意到geni.com有一个相当深入的API来处理这个问题。也许使用他们的API进行编码可以提高代码重用性...
-- 家谱树 -- 家谱树 可能已经足够满足您的需求了。您可以使姻亲链接化,点击他们的姓名后,图形将重新绘制,以便您可以看到他们的谱系。
-- 括号布局树 --
类似于家谱树,但是双向的,括号布局树 让您处理“这是我的父母、祖父母、子女、孙子女”等类型的视图。像家谱树一样,您可以使个人链接到重新定位括号节点。
-- 基于力的布局 --
有一些有趣的基于力的布局看起来很有前途。看看 这个具有智能标签的基于力的布局示例。调整算法以确定“力”的方式可能会使其成为一个非常美丽的树,旧一代在新一代上面或下面。
-- 群集树状图(失败原因) --
我见过的d3.js布局最适合家族谱系的假设单个节点是父节点,而您需要将父节点表示为两个节点的组合(在视觉上为“T”)。一个是您家族树的成员节点,另一个是代表姻亲的浮动节点。调整群集树状图以实现此目的应该是可行的,但需要进行重大修改。
如果你或其他人解决了这个问题,请告诉我。我想看到(并从中获益),如果可行,可能能够为之做出贡献。
至于具体实现,mj8591提出了 与此类似的家谱树问题。 然而,幸运的是,这个问题包含了一个fiddle(所有js代码),其中包含了您需要的大多数或全部组件,而来自mdml的回答则包括了另一个fiddle,增加了每个节点的更细致的"可点击性"。
再次强调,这不是魔法,但希望这些资源足以为您提供良好的起点!

4

我尝试过 dtree 并且很喜欢它。然而,当你添加了几代人之后,水平显示可能会使整体显示非常大并且难以操作。相反,我使用了 Reingold–Tilford Tree。这个树的一个缺点是每个节点只能有一个父节点:配偶不能在一起显示。为了克服这个限制,我调整了 JSON,将配偶合并为一个实体(例如:"丈夫-妻子"),然后将其发送到树中。


2

你的例子存在问题,即每个孩子只有一个父母。这可以很容易地通过D3(或Google组织图表更容易)来解决,但问题在于它无法显示两个父母。 - Lau Frie

1

0

我不知道这是否对你有所帮助,因为你说你要使用d3.js,但是还有另一个工具你可能想要考虑使用,叫做jsplumb。它似乎非常适合这种项目:主页。他们也有一些不错的教程。还有一个类似文档的,和另一个更交互式的

就像我说的,如果现在换技术还不算太晚,这个工具值得一试。它全部都是html、css和javascript,所以转换应该不会很困难。


2
建议更改工具并不是一个答案。 - Dave Alperovich
2
当然,如果使用另一个工具可以更轻松地解决问题,那么建议使用另一个工具也是有用的。严格来说,得到高票的答案“dTree”也是另一个工具。它是基于d3构建的,但仍然是另一个工具......此外,问题的提出方式似乎表明在“研究”中,d3似乎是最适合这项工作的工具。 - Adrian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接