2011-09-14 136 views
1

我試圖在D3示例中動態更改模擬詳細信息https://github.com/mbostock/d3/blob/master/examples/force/force-multi-foci.html。我把一個複選框,然後(在http://pastebin.com/k4P0uzHK完整的代碼)動態分配的節拍處理程序如下:動態更改Javascript D3佈局模擬

$("#chkBox").change(function(){ 
    if ($(this).is(':checked')) { 
    force.on("tick", forceTick); 
    } else { 
    force.on("tick", forceTick2); 
    } 
}); 

forceTick = function(e) { 
    // Push different nodes in different directions for clustering. 
    var ky = 400 * e.alpha; 
    var kx = 20 * e.alpha; 
    hLinks.forEach(function(hlink) { 
    var yB = hlink.source.y, yT = hlink.target.y; 
    if (yB<(yT+20)) { hlink.source.y += Math.min(ky,yT+20-yB); hlink.target.y -= Math.min(ky,yT+20-yB);} 
    var xB = hlink.source.x, xT = hlink.target.x; 
    if (xB<(xT-20)) { hlink.source.x += Math.min(kx,xT-20-xB); hlink.target.x -= Math.min(kx,xT-20-xB);} 
    if (xB>(xT+20)) { hlink.source.x -= Math.min(kx,xB-xT-20); hlink.target.x += Math.min(kx,xB-xT-20);} 

    }); 

    node.attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }); 

    link.attr("x1", function(d) { return d.source.x; }) 
     .attr("y1", function(d) { return d.source.y; }) 
     .attr("x2", function(d) { return d.target.x; }) 
     .attr("y2", function(d) { return d.target.y; }); 
}; 


forceTick2 = function(e) { 

    node.attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }); 

    link.attr("x1", function(d) { return d.source.x; }) 
     .attr("y1", function(d) { return d.source.y; }) 
     .attr("x2", function(d) { return d.target.x; }) 
     .attr("y2", function(d) { return d.target.y; }); 
}; 

但實際上似乎只有處理程序給出的首部作品。有沒有辦法動態控制模擬?

回答

4

用於強制佈局的on運算符(以及其他使用d3.dispatch的運算符)添加了事件偵聽器。它不會替代現有的事件偵聽器。強制佈局當前不公開一個機制來刪除或替換現有的事件偵聽器。

這是一個錯誤。我打算讓佈局的on運算符與選擇一致,通過多次調用on,您可以添加,替換和移除事件偵聽器。如果您使用名稱空間(例如「tick.foo」和「tick.bar」),您仍然可以註冊多個偵聽器。

與此同時,簡單的解決方法是使用單一方法作爲您的滴答聲監聽器,但隨後使用一些全局布爾值來確定您想要爲每個滴答滴答選擇哪種行爲。在你的情況,像這樣的東西:

if (checked) { 
    … clustering … 
} 
… update link positions … 
… update node positions … 

而加號,這消除了代碼重複。 :)

+1

謝謝,雖然現在我想想, '.on(「tick」只是改變了可視化,並不能阻止內部模擬,如果我們可以從外部動態地改變'alpha'會更好。 – highBandWidth

1

你可以在這裏看到的一個很好的例子爲d3.v4: https://bl.ocks.org/steveharoz/8c3e2524079a8c440df60c1ab72b5d03

你可以看到這裏的重要功能:

// add forces to the simulation 
function initializeForces() { 
    // add forces and associate each with a name 
    simulation 
    .force("link", d3.forceLink()) 
    .force("charge", d3.forceManyBody()) 
    .force("collide", d3.forceCollide()) 
    .force("center", d3.forceCenter()) 
    .force("forceX", d3.forceX()) 
    .force("forceY", d3.forceY()); 
    // apply properties to each of the forces 
    updateForces(); 
} 

// apply new force properties 
function updateForces() { 
    // get each force by name and update the properties 
    simulation.force("center") 
    .x(width * forceProperties.center.x) 
    .y(height * forceProperties.center.y); 
    simulation.force("charge") 
    .strength(forceProperties.charge.strength * forceProperties.charge.enabled) 
    .distanceMin(forceProperties.charge.distanceMin) 
    .distanceMax(forceProperties.charge.distanceMax); 
    simulation.force("collide") 
    .strength(forceProperties.collide.strength * forceProperties.collide.enabled) 
    .radius(forceProperties.collide.radius) 
    .iterations(forceProperties.collide.iterations); 
    simulation.force("forceX") 
    .strength(forceProperties.forceX.strength * forceProperties.forceX.enabled) 
    .x(width * forceProperties.forceX.x); 
    simulation.force("forceY") 
    .strength(forceProperties.forceY.strength * forceProperties.forceY.enabled) 
    .y(height * forceProperties.forceY.y); 
    simulation.force("link") 
    .id(function(d) {return d.id;}) 
    .distance(forceProperties.link.distance) 
    .iterations(forceProperties.link.iterations) 
    .links(forceProperties.link.enabled ? graph.links : []); 

    // updates ignored until this is run 
    // restarts the simulation (important if simulation has already slowed down) 
    simulation.alpha(1).restart(); 
}