【问题标题】:Adding child elements to specific nodes in a force-directed graph using d3js使用 d3js 将子元素添加到力导向图中的特定节点
【发布时间】:2018-05-21 19:21:26
【问题描述】:

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

我通过使用 D3s 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 节点。如果我继续调用 draw 函数,它会在我的 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>

感谢任何帮助。

【问题讨论】:

  • 不是针对您的特定问题的直接答案,但您见过"How to create SVG elements of different types based on data?"吗?
  • 发表了答案,请看。如果它不起作用,请帮助我提供在 fiddler/plunker 上复制的问题的链接。
  • 第一次调用 draw() 时是否会出现多个子节点 - 或者您是否必须多次调用它才能出现(最初)节点或出现多个子节点?

标签: javascript d3.js force-layout


【解决方案1】:

在 d3 wiki 上再次阅读 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()
}

【讨论】:

    猜你喜欢
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    相关资源
    最近更新 更多