【问题标题】:Is there a way to have unlinked Nodes to not be as spread out in a radius?有没有办法让未链接的节点不分散在半径范围内?
【发布时间】:2019-10-22 18:01:19
【问题描述】:

注意: 我将它从 Javascript 改编为 Typescript。通常一切实际上都是javascript。我在角度使用它,但我相信这超出了问题的范围。我添加了 [javascript] 标记,因为虽然这是 TS,但答案可以是 javascript 和改编。

编辑:我认为这个问题可能与收费有关。 Charge 允许节点有时间自行设置,但我认为它是 -130,与任何东西无关的节点只是被大幅推开,这是我不喜欢的。我在想我可能需要找到一种方法来选择性地为节点充电,但我确实认为保持充电是有用的

在运行强制有向图时,我注意到了一些有趣的事情。如果节点是链接的,它会在流动的庄园中创建一个很好的数据有机表示。任何未链接的节点,它们只是围绕对象围成一圈,看似等间距,就好像所有节点都未链接一样。如果我遇到的问题是这个非链接圆的半径太大以至于它在视口之外。是否有一种强制定向方式可以使这个默认值更容易使用,例如但不限于较小的半径或坐在链接对象的一侧。

无论哪种方式,我都想让未链接的设备在视口内重置,因为人们不一定知道缩小。

我还注意到,如果我重绘屏幕,节点有时会产生速度并缓慢移出屏幕,随着网格刷新,这似乎是不正确的超时。我不确定为什么会发生这种情况。我认为模拟节点半径可能与以下代码或“ticker”变量有关:

this.simulation = d3.forceSimulation().force("charge", d3.forceMainBody().strength(FORCES.CHARGE));
this.simulation.on("tick", function(){ ticker.emit(this); });

甚至可能是力“中心”功能。

this.simulation.force('centers', d3.forceCenter(options.width /2, options.height /2));

我将链接一张图片,显示发生的情况(但已缩小)以及拓扑代码。

import { Link } from './link';
import { Node } from './node';
import * as d3 from 'd3';
import { EventEmitter } from '@angular/core';

const FORCES = {
    GRAVITY: 0.1,
    FRICTION: 0.9,
    CHARGE: -130,
    LINKDISTANCE: 50,
    LINKSTRENGTH: 0.2,
    CHARGEDISTANCE: Infinity,
    THETA: 0.8
};

export class ForceDirectedGraph {

    public ticker: EventEmitter<d3.Simulation<Node,Link>> = new EventEmitter<d3.Simulation<Node,Link>>();
    public simulation: d3.Simulation<any, any>;

    constructor(public nodes: Node[], public links: Link[], options: {width, height}){
        this.initSimulation(options);
    }

    initNodes() {
        if (!this.simulation) {
            throw new Error ('Simulation was noot Initialized.');
        }
        this.simulation.nodes(this.nodes);
    }
    initLinks() {
        if (!this.simulation) {
            throw new Error ('Simlulation was not Initialized');
        }
        this.simulation.force('links', d3.forceLink(this.links).strength(FORCES.LINKSTRENGTH));
    }

    initSimulation(options: any) {
        if (!options || !options.width || !options.height) {
            throw new Error("Missing Options On Initialize");
        }

        if (!this.simulation) {
            const ticker = this.ticker;
            this.simulation = d3.forceSimulation()
                .force("charge", d3.forceManyBody()
                    .strength(FORCES.CHARGE));
            this.simulation.on('tick', function() {
                ticker.emit(this);
            });
            this.initNodes();
            this.initLinks();
        }

        this.simulation.force('centers', d3.forceCenter(options.width / 2, options.height / 2))

        this.simulation.restart();
    }
}

【问题讨论】:

    标签: javascript typescript d3.js


    【解决方案1】:

    您可以添加radial force 并仅将其应用于断开连接的节点。

    this.simulation
        .force('radial', d3.forceRadial(Math.min(width, height) / 2 - 10)
        .strength(d => isConnected(d) ? 0 : 0.2))
    

    其中isConnected 是确定节点是否已连接的某个函数。

    【讨论】:

    • 'd' 是一个节点引用吗?
    • 我正在做一些初步测试。它实际上看起来有效。我向 Node 添加了一个属性,该属性在我构建链接时确定,然后我这样做:d =&gt; d.hasLink ? 0 : 0.2,它实际上看起来相当不错。我只是从来没有弄清楚该属性将被定义并设置为不会产生额外的运行时成本。效果很好,我给你答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-03
    • 2018-07-01
    相关资源
    最近更新 更多