2017-02-25 57 views
1

我一直在使用D3的动力布局,以创建向中间力量做了一个分组气泡图,就像这样:D3增加力量单个节点

var forceStrength = 0.03; 
    var center = { x: widthBubbles/2, y: heightBubbles/2 }; 

    var simulation = d3.forceSimulation() 
    .velocityDecay(0.2) 
    .force('x', d3.forceX().strength(forceStrength).x(center.x)) 
    .force('y', d3.forceY().strength(forceStrength).y(center.y)) 
    .force('charge', d3.forceManyBody().strength(charge)) 
    .on('tick', ticked); 

    function charge(d) { 
    return -forceStrength * Math.pow(d.r, 2.0); 
    } 

    function ticked() { 
    bubbles 
     .attr('cx', function (d) { return d.x; }) 
     .attr('cy', function (d) { return d.y; }); 
    } 

我的图表看起来类似于这样:Gates Foundation Educational Spending

我希望能够在单个节点上单击时施加一个力,以便点击的节点将移动到另一个区域。在D3的文档中,有一些称为“定位力”的东西,根据文档打算用于多个节点:

虽然这些力可用于定位各个节点,但它们主要用于适用于所有(或大多数)节点的全球力量。

所以我的问题是如果有一种方法可以将力量应用于D3中的单身节点。

+1

这可能只是[*“碰撞检测丢失后切换​​(d3v4)”*](/ q/41479452)中讨论的解决方案的特例。 – altocumulus

+0

它可能是相似的,但我的问题是如何改变只有一个节点的力量。 – martin36

回答

0

我通过创建一个函数,这是所谓的每点击一个气泡时间解决了这个问题:

//Function for moving bubbles when selected 
    function moveSelectedBubbles() { 
    simulation.force('x', d3.forceX().strength(forceStrength).x(function(d){ 
     //Check if bubble is selected 
     return (selectedCountries.indexOf(d.data.country) >= 0) ? selectedCenter.x : center.x; 
    })); 

    simulation.alpha(1).restart(); 

    } 

但是这个功能被选择的气泡每次设置每个节点的力。也许有一种更有效的方式来处理案件。

+0

从你的解决方案看来,你的力量实际上是作用于所有节点的,因为如果它没有被选中,你将它设置为'center.x'。如果情况并非如此,并且您想仅隔离一个节点/一组节点,那么最近有一个很酷的mbostock块:https://bl.ocks.org/mbostock/b1f0ee970299756bc12d60aedf53c13b我发现它很有用。另外,我认为你应该能够在'forceX(here)'函数中移动你的'.x(函数(d)...'代码来简化事情(我不认为你应该设置这个力每一个点击处理程序btw) – ibgib

+0

还有一件事:你也可以在'd'对象本身存储一个临时标志,例如'd.isSelected',并对其进行过滤,而不是每次重新计算'indexOf'(这需要你也要处理何时将这个标志设置为false,很明显。) – ibgib

+1

谢谢你的评论,我会检查一下。 – martin36