使用d3js向力导向图中的特定节点添加子元素

6

我希望根据节点类型向我的节点添加不同的子元素。因此,该节点具有名为type的属性。所有节点都应由一个包含相关子元素的g元素组成。

我尝试使用D3的filter功能,但我卡住了,因为我的代码不仅一次添加子元素,而是多次添加所需的子元素(与我拥有的节点数量相同)。所以我想我在选择方面做错了些什么。

我的图形的节点和链接会随时间改变,因此我所做的是首先存储选择,当一个节点被添加到self.nodes时,我调用绘制函数(我将省略链接代码)。

self.domNodes = this.svg.append('g').attr('class', 'nodes').selectAll('.node')

function draw() {
    self.domNodes = self.domNodes.data(self.nodes, (node) => node.id)
    self.domNodes.exit().remove()

    // all nodes
    self.domNodes.enter()
      .append('g')
      .attr('class', (node) => `node ${node.type}`)
      .merge(self.domNodes)

    // contributions
    self.domNodes.filter((d) => d.type === 'contribution')
      .append('circle')
      .attr('r', 4)
      .attr('fill', 'blue')

    // persons
    self.domNodes.filter((d) => d.type === 'person')
      .append('other elements and attributes...')

    self.simulation.nodes(self.nodes)
    self.simulation.force('link').links(self.links)
    self.simulation.alpha(1).restart()
}

它的功能是区分personcontribution,并为此类型添加我想要的元素,但它不仅在每个g节点中添加一个元素,而是添加多个(我有的节点数)到每个g节点中。如果我继续调用绘制函数,它将在我的

<svg>
    <g>
        <g class="nodes">
            <g class="node contribution" transform="translate(466, 442)">
                <circle r="4" fill="blue"></circle>
                <circle r="4" fill="blue"></circle>
                <circle r="4" fill="blue"></circle>
            </g>
            <g class="node contribution" transform="translate(466, 442)">
                <circle r="4" fill="blue"></circle>
                <circle r="4" fill="blue"></circle>
                <circle r="4" fill="blue"></circle>
            </g>
            <g class="node contribution" transform="translate(466, 442)">
                <circle r="4" fill="blue"></circle>
                <circle r="4" fill="blue"></circle>
                <circle r="4" fill="blue"></circle>
            </g>
            <g class="node person" transform="translate(400, 200)">
                <someotherthings></someotherthings>
                <someotherthings></someotherthings>
            </g>
            <g class="node person" transform="translate(400, 200)">
                <someotherthings></someotherthings>
                <someotherthings></someotherthings>
            </g>
        </g>
    </g>
</svg>

我在这里做错了什么?我只想在每个节点中添加一个circle和其他元素,但它们似乎被重复添加了。
<svg>
    <g>
        <g class="nodes">
            <g class="node contribution" transform="translate(466, 442)">
                <circle r="4" fill="blue"></circle>
            </g>
            <g class="node contribution" transform="translate(466, 442)">
                <circle r="4" fill="blue"></circle>
            </g>
            <g class="node contribution" transform="translate(466, 442)">
                <circle r="4" fill="blue"></circle>
            </g>
            <g class="node person" transform="translate(400, 200)">
                <someotherthings></someotherthings>
            </g>
            <g class="node person" transform="translate(400, 200)">
                <someotherthings></someotherthings>
            </g>
        </g>
    </g>
</svg>

非常感谢您的帮忙。


虽然这不是对你具体问题的直接回答,但你看过"如何根据数据创建不同类型的SVG元素?"吗? - altocumulus
已发布答案,请查看。如果不起作用,请帮我提供在fiddler/plunker上复制问题的链接。 - Vipin Kumar
当您第一次调用draw()时,多个子节点是否出现 - 或者您必须调用它多次以使节点出现(最初)或多个子节点存在? - Andrew Reid
1个回答

2

再次阅读d3维基上关于selection.data的内容后,我最终弄明白了它的用法。

我预先合并了我的笔记,所以我的选择器包括进入节点和更新节点。现在我做的第一件事是创建进入节点,然后对它们进行选择和过滤,最后将它们合并。

function draw() {
    self.domNodes = self.domNodes.data(self.nodes, (node) => node.id)
    self.domNodes.exit().remove()

    // all nodes
    const enterNodes = self.domNodes.enter()
      .append('g')
      .attr('class', (node) => `node ${node.type}`)

    // contributions
    enterNodes.filter((d) => d.type === 'contribution')
      .append('circle')
      .attr('r', 4)
      .attr('fill', 'blue')

    // persons
    enterNodes.filter((d) => d.type === 'person')
      .append('other elements and attributes...')

    self.domNodes = self.domNodes.merge(enterNodes)

    self.simulation.nodes(self.nodes)
    self.simulation.force('link').links(self.links)
    self.simulation.alpha(1).restart()
}

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